虽然这是道普及组的题,但解决的过程还真是挺曲折的。。。QwQ
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1983
也捣鼓了很久的图论了(其实并没有多久),打算把这道题作为一个分界点,转去学一会DP。没想到,看完题目,我的第一反应并不是图论知识。
最初的思路是这样,对于每个站点,先设置级别为1,然后对于读入的每趟列车,因为读入的车站级别一定比没读入的高,就检查每个车站,不合格就修改。结果只有20分,仔细一想确实不对。对于每趟列车,读入车站的级别应当保证一直比未读入的高,然而这种只考虑本趟列车的做法,显然可能会与之前的产生冲突。
然后就开始考虑图论怎么做,比较容易想到的是将大小关系用边来表示,然后跑拓扑排序(其实一开始就想到了),令人不安的是建图过程,复杂度极高!没办法,还是硬着头皮写吧。但是只有60分,提示是运行时错误,那肯定数组开小了。最多有1000个点,又因为是有向图且不会出现两个点之间有两条边的情况,所以边数不会超过1000*(1000-1)/2。把数组稍稍调大一点,咦,怎么成了70分。
看题解。。。哦!原来在读入边的过程中,每条边可能被读入多次!这也就解释了为什么数组会小,内存会爆。这样最多会处理1000*(1000-1)/2条边,复杂度也没那么高。加个标志数组,标志被处理过的数组就能A掉。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 inline int get_num() { 8 int num;char c; 9 while((c=getchar())=='\n'||c==' '||c=='\r'); 10 num=c-'0'; 11 while(isdigit(c=getchar())) num=num*10+c-'0'; 12 return num; 13 } 14 const int maxn=1005,maxm=5e5+5; 15 int n,m,stop[maxn],vis[maxn],head[maxn],eid,vis_edge[maxn][maxn],ind[maxn],level[maxn],ans; 16 struct edge { 17 int v,next; 18 } E[maxm]; 19 void insert(int u,int v) { 20 E[eid].v=v; 21 E[eid].next=head[u]; 22 head[u]=eid++; 23 } 24 queue<int> q; 25 void topo() { 26 for(int i=1;i<=n;++i) level[i]=1; 27 for(int i=1;i<=n;++i) if(!ind[i]) q.push(i); 28 while(!q.empty()) { 29 int u=q.front();q.pop(); 30 for(int p=head[u];p+1;p=E[p].next) { 31 int v=E[p].v; 32 level[v]=max(level[v],level[u]+1); 33 if(!(--ind[v])) q.push(v); 34 } 35 ans=max(ans,level[u]); 36 } 37 } 38 int main() { 39 n=get_num();m=get_num(); 40 int cnt,sta,s=-1,t=-1; 41 memset(head,-1,sizeof(head)); 42 for(int i=1;i<=m;++i) { 43 memset(stop,0,sizeof(stop)); 44 memset(vis,0,sizeof(vis)); 45 cnt=get_num(); 46 for(int j=1;j<=cnt;++j) { 47 stop[j]=(sta=get_num()),vis[sta]=1; 48 if(j==1) s=sta; 49 else if(j==cnt) t=sta; 50 } 51 for(int j=s;j<=t;++j) if(!vis[j]) { 52 for(int k=1;k<=cnt;++k) 53 if(!vis_edge[j][stop[k]]) insert(j,stop[k]),++ind[stop[k]],vis_edge[j][stop[k]]=1; 54 } 55 } 56 topo(); 57 printf("%d",ans); 58 return 0; 59 }