原题链接
考察:拓扑排序
思路:
等级低与等级高之间建立边.比如区间[1,6]之间停靠了(1,3,5,6).那么在(1,3,5,6)与(2,4)之间两两间加一条边.最后拓扑排序即可.
但是这样会TLE.时间复杂度O(109),空间复杂度极限O(500*500*1000).需要进一步优化.
但是注意初始化等级时,虚点不能初始化为1,因为不一定有入度.
Code
#include <iostream>
#include <cstring>
#include <set>
using namespace std;
const int N = 1010;
int h[N<<1],idx,n,m,d[N<<1],q[N<<1],level[N<<1],p;
set<int> s;
struct Road{
int fr,to,ne,w;
}road[N*N<<2];
void add(int a,int b,int w)
{
road[idx].w = w,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
void topsort()
{
int hh=0,tt=-1;
for(int i=1;i<=p;i++) if(!d[i]) q[++tt] = i;
while(hh<=tt)
{
int u = q[hh++];
for(int i=h[u];~i;i=road[i].ne)
{
int v = road[i].to;
if(--d[v]==0) q[++tt] = v;
}
}
}
void solve()
{
int res = 0;
for(int i=1;i<=n;i++) level[i] = 1;//存在没有入度的虚拟点
for(int i=0;i<p;i++)
{
int u = q[i];
res = max(res,level[u]);
//if(level[u]==6) printf("%d\n",u);
for(int j=h[u];~j;j=road[j].ne)
{
int v = road[j].to;
level[v] = max(level[v],level[u]+road[j].w);
// printf("%d %d %d %d\n",road[j].fr,road[j].to,road[j].w,level[v]);
}
}
printf("%d\n",res);
}
int main()
{
memset(h,-1,sizeof h);
scanf("%d%d",&n,&m);
p = n+1;
while(m--)
{
int sz,l=3*n,r=0;
scanf("%d",&sz);
s.clear();
for(int i=1;i<=sz;i++)
{
int x; scanf("%d",&x);
s.insert(x);
add(p,x,1);
l = min(x,l);
r = max(r,x);
d[x]++;
}
for(int i=l+1;i<r;i++)
if(!s.count(i))
add(i,p,0),d[p]++;
p++;
}
topsort();
solve();
return 0;
}