NOIp2013 车站分级 【拓扑排序】By cellur925
我们注意到,题目中说:如果这趟车次停靠了火车站 x,则始发站、终点站之间所有级别大于等于火车站x的都必须停靠。有阶级关系,满满的拓扑排序氛围。但是,如果我们按大于等于的关系连,等于的情况就会连双向边,这不利于我们在有向无环图中(DAG)进行拓扑排序。于是我们不妨换一种思路,将所有小于当前火车站级别的车站向输入的车站序列间连一条有向边。之后边拓扑排序边更新车站级数即可。
注意建图的细节过程。首先对于每个车次,我们应该从起点出发终点结束,也就是代码中的w[1]和w[n];其次由于有很多车次 ,所以可能发生建了重边的情况,所以另需要数组来记录边 有没有被连过。
在进行拓扑排序时,将一个pair插入队列,入度为0的点一定级别最低 ,它为1,对于每个从它出发得到的点,我们把它的级别+1即可。
同杂务一题一样,拓扑保证最小性质,而取max保证考虑全面。
Code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<queue> 5 #include<utility> 6 7 using namespace std; 8 9 int n,m,tot,ans; 10 int head[1009],du[1009],w[1009],vis[1009]; 11 bool jud[1009][1009]; 12 struct node{ 13 int to,next; 14 }edge[1000900]; 15 16 void add(int x,int y) 17 { 18 edge[++tot].to=y; 19 edge[tot].next=head[x]; 20 head[x]=tot; 21 } 22 23 void topo() 24 { 25 queue<pair<int,int> >q; 26 for(int i=1;i<=n;i++) 27 if(!du[i]) q.push(make_pair(i,1)); 28 while(!q.empty()) 29 { 30 int u=q.front().first; 31 int val=q.front().second;q.pop(); 32 for(int i=head[u];i;i=edge[i].next) 33 { 34 int v=edge[i].to; 35 if(--du[v]==0) q.push(make_pair(v,val+1)); 36 ans=max(ans,val+1); 37 } 38 } 39 } 40 41 int main() 42 { 43 scanf("%d%d",&n,&m); 44 for(int p=1;p<=m;p++) 45 { 46 memset(vis,0,sizeof(vis)); 47 memset(w,0,sizeof(w)); 48 int opt=0; 49 scanf("%d",&opt); 50 for(int i=1;i<=opt;i++) 51 scanf("%d",&w[i]),vis[w[i]]=1; 52 for(int i=w[1];i<=w[opt];i++) 53 { 54 if(!vis[i]) 55 for(int j=1;j<=opt;j++) 56 if(!jud[i][w[j]]) add(i,w[j]),du[w[j]]++,jud[i][w[j]]=1; 57 } 58 } 59 /* for(int i=1;i<=n;i++) 60 for(int j=1;j<=n;j++) 61 printf("%d %d :=%d\n",i,j,jud[i][j]); 62 return 0; 63 */ topo(); 64 printf("%d",ans); 65 return 0; 66 } 67 //判断边有没有连重
独立意志与自由思想是必须争的,且须以生死力争。