【NOIP2013】车站分级

虽然这是道普及组的题,但解决的过程还真是挺曲折的。。。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 }
AC代码

猜你喜欢

转载自www.cnblogs.com/Mr94Kevin/p/9588110.html