专题训练之拓步排序

推荐几个博客:https://blog.csdn.net/dm_vincent/article/details/7714519 拓扑排序的原理及其实现php

https://blog.csdn.net/u012860063/article/details/38017661 拓扑排序的几种写法
node

https://blog.csdn.net/shahdza/article/details/7779389 拓扑排序题集c++

 

1.基于DFS的拓扑排序:通常适用于数据较小而且须要判断有无环的状况算法

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=150;  6 int n,vis[maxn],topo[maxn],cnt;  7 bool g[maxn][maxn],flag;  8 
 9 void dfs(int u) 10 { 11     if ( vis[u]<0 ) { 12         flag=false; 13         return; 14  } 15     if ( vis[u]>0 ) return; 16     else vis[u]=-1; //表示当前还在访问中 
17     for ( int v=1;flag&&v<=n;v++ ) { 18         if ( g[u][v] ) dfs(v); 19  } 20     topo[cnt--]=u; //保存下来 
21     vis[u]=1; //访问完成 
22 } 23 
24 void toposort() 25 { 26     int i,j,k; 27     flag=true; 28     memset(vis,0,sizeof(vis)); //vis为0表示初从未访问过,为1表示已经已经访问完成,为-1表示当前还在访问中 
29     cnt=n; 30     for ( int i=1;i<=n&&flag;i++ ) { 31         if ( vis[i]==0 ) dfs(i); 32  } 33 } 34 
35 int main() 36 { 37     int i,m,x,y; 38     while ( scanf("%d%d",&n,&m)!=EOF ) { 39         memset(g,false,sizeof(g)); 40         while ( m-- ) { 41             scanf("%d%d",&x,&y); 42             g[x][y]=true; //g存储两个点的关系 
43  } 44  toposort(); 45         for ( int i=1;i<n;i++ ) printf("%d",topo[i]); 46         printf("%d\n",topo[n]); 47  } 48     return 0; 49 }
基于DFS的toposort

模板题(HDOJ3342)http://acm.hdu.edu.cn/showproblem.php?pid=3342数组

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=110;  6 int vis[maxn],topo[maxn],n,cnt;  7 bool g[maxn][maxn],flag;  8 
 9 void dfs(int u) 10 { 11     if ( vis[u]<0 ) { 12         flag=false; 13         return; 14  } 15     if ( vis[u]>0 ) return; 16     else vis[u]=-1; 17     for ( int v=1;v<=n&&flag;v++ ) { 18         if ( g[u][v] ) dfs(v); 19  } 20     topo[cnt--]=u; 21     vis[u]=1; 22 } 23 
24 void toposort() 25 { 26     memset(vis,0,sizeof(vis)); 27     flag=true; 28     cnt=n; 29     for ( int i=1;i<=n;i++ ) { 30         if ( vis[i]==0 ) dfs(i); 31  } 32 } 33 
34 int main() 35 { 36     int m,i,j,k,x,y; 37     while ( scanf("%d%d",&n,&m)!=EOF && n ) { 38         memset(g,false,sizeof(g)); 39         for ( i=1;i<=m;i++ ) { 40             scanf("%d%d",&x,&y); 41             x++;y++; 42             g[x][y]=true; 43  } 44  toposort(); 45         if ( flag ) printf("YES\n"); 46         else printf("NO\n"); 47  } 48     return 0; 49 }
HDOJ3342

 

2.kahn算法求拓扑排序ide

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 priority_queue<int,vector<int>,greater<int> >que;  8 const int maxn=505;  9 vector<int>G[maxn]; 10 int ans[maxn],ind[maxn],n; 11 
12 void toposort() 13 { 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=0; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[++cnt]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     for ( int i=1;i<=n;i++ ) { 29         printf("%d",ans[i]); 30         if ( i==n ) printf("\n"); 31         else printf(" "); 32  } 33 } 34 
35 int main() 36 { 37     int m,i,j,k,x,y; 38     while ( scanf("%d%d",&n,&m)!=EOF ) { 39         for ( i=1;i<=n;i++ ) G[i].clear(); 40         memset(ind,0,sizeof(ind)); 41         while ( m-- ) { 42             scanf("%d%d",&x,&y); 43  G[x].push_back(y); 44             ind[y]++; 45  } 46  toposort(); 47  } 48     return 0; 49 }
Kahn

 

作法:spa

首先统计每一个结点的入度。将度为0的结点编号放入队列 / 优先队列中。
而后进行循环:
  1. 取出队头结点,存入ans数组。
  2. 而后“删除与该点相连的边”,即将从这个点出发到其余点的边所在的终点的入度-1;
  3. 若是-1之后,终点的入度变为了0,那么将终点的编号入队列。
  4. 不断循环直到队列为空/ans数组保存了n个元素

模板题(HDOJ1285)http://acm.hdu.edu.cn/showproblem.php?pid=1285.net

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 priority_queue<int,vector<int>,greater<int> >que;  8 const int maxn=505;  9 vector<int>G[maxn]; 10 int ans[maxn],ind[maxn],n; 11 
12 void toposort() 13 { 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=1; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[cnt++]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     for ( int i=1;i<=n;i++ ) { 29         printf("%d",ans[i]); 30         if ( i==n ) printf("\n"); 31         else printf(" "); 32  } 33 } 34 
35 int main() 36 { 37     int m,i,j,k,x,y; 38     while ( scanf("%d%d",&n,&m)!=EOF ) { 39         for ( i=1;i<=n;i++ ) G[i].clear(); 40         memset(ind,0,sizeof(ind)); 41         while ( m-- ) { 42             scanf("%d%d",&x,&y); 43  G[x].push_back(y); 44             ind[y]++; 45  } 46  toposort(); 47  } 48     return 0; 49 }
HDOJ1285

 

总结:拓扑序列是由某个集合上的一个偏序获得该集合上的一个全序。题目每每给定一个偏序。而全序每每是按照必定的要求才能获得的(这样的要求每每体如今优先队列中须要维护的变量上)。通常是要求字典序最小,有时候也会有不少附加条件,都是为了获得这个全序。code

练习题:对象

1.(HDOJ4857)http://acm.hdu.edu.cn/showproblem.php?pid=4857

分析:该题字典序最小不一样,该题的目的是不断想办法使当前全部未访问过的节点中编号最小的先出来。即存在6-4-1和3-9-2,由于当前存在的编号最小的是1,全部先让6 4 1先出来,6 4出来的目的是使1尽早出来。所以该题只须要反向建图,每次取出编号大的保存在ans数组的尾端。最关键的一点是小的头部不必定排在前面,而大的尾部必定排在后面

推荐一个解释较好的博客:https://blog.csdn.net/u012861385/article/details/38059515

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=30010;  8 vector<int>G[maxn];  9 int ans[maxn],ind[maxn],n; 10 
11 void toposort() 12 { 13     priority_queue<int>que; 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=n; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[cnt--]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     for ( int i=1;i<=n;i++ ) { 29         printf("%d",ans[i]); 30         if ( i==n ) printf("\n"); 31         else printf(" "); 32  } 33 } 34 
35 int main() 36 { 37     int m,i,j,k,x,y,T; 38     scanf("%d",&T); 39     while ( T-- ) { 40         scanf("%d%d",&n,&m); 41         for ( i=1;i<=n;i++ ) G[i].clear(); 42         memset(ind,0,sizeof(ind)); 43         while ( m-- ) { 44             scanf("%d%d",&x,&y); 45  G[y].push_back(x); 46             ind[x]++; 47  } 48  toposort(); 49  } 50     return 0; 51 }
HDOJ4857

 

2.(HDOJ2647)http://acm.hdu.edu.cn/showproblem.php?pid=2647

题意:有n我的,m条要求,每条要求的内容为(x,y),即x要求本身的奖金比y高,求老板最少须要发多少奖金,每人至少888,当有矛盾时输出-1

分析:当最后ans数组中保存的数cnt少于n时说明出现了环,此时矛盾输出-1。能够设置一个rk数组表示每一个人的“等级”,最后第i我的得到的奖金为888+rk[i]。rk数组初始化为-1,刚开始入度为0的点rk为0,对于边(u,v)上的v点来讲,rk[v]=max(rk[v],rk[u]+1)。而对于整个图来讲须要反向建图。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=1e4+10;  8 typedef long long ll;  9 vector<int>G[maxn]; 10 int ans[maxn],ind[maxn],n,rk[maxn]; 11 
12 void toposort() 13 { 14     queue<int>que; 15     while ( !que.empty() ) que.pop(); 16     for ( int i=1;i<=n;i++ ) { 17         if ( ind[i]==0 ) { 18  que.push(i); 19             rk[i]=0; 20  } 21  } 22     int cnt=0; 23     while ( !que.empty() ) { 24         int tmp=que.front(); 25  que.pop(); 26         ans[++cnt]=tmp; 27         for ( int i=0;i<G[tmp].size();i++ ) { 28             int v=G[tmp][i]; 29             ind[v]--; 30             rk[v]=max(rk[v],rk[tmp]+1); 31             if ( ind[v]==0 ) que.push(v); 32  } 33  } 34     if ( cnt<n ) printf("-1\n"); 35     else { 36         ll sum=0; 37         for ( int i=1;i<=n;i++ ) sum+=rk[i]; 38         sum=(ll)888*n+sum; 39         printf("%lld\n",sum); 40  } 41 } 42 
43 int main() 44 { 45     int m,i,j,k,x,y; 46     while ( scanf("%d%d",&n,&m)!=EOF ) { 47         for ( i=1;i<=n;i++ ) G[i].clear(); 48         memset(ind,0,sizeof(ind)); 49         memset(rk,-1,sizeof(rk)); 50         while ( m-- ) { 51             scanf("%d%d",&x,&y); 52  G[y].push_back(x); 53             ind[x]++; 54  } 55  toposort(); 56  } 57     return 0; 58 }
HDOJ2647

 

3.(POJ3687)http://poj.org/problem?id=3687

题意:有n个球,每一个球的重量为i(从1到n),如今要给每一个球贴标签(编号),没有两个编号是同样的;有m个要求,要求(x,y)表示第x个球的标签要小于第y个球。

分析:大体同HDOJ4857,须要反向建图,由于该题也是须要当前重量最小的球尽可能靠前

注意:输出一行。第i个表示的是第i个球的编号,而不是拓步排序中的顺序

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=205;  8 vector<int>G[maxn];  9 int ans[maxn],ind[maxn],n,pos[maxn]; 10 
11 void toposort() 12 { 13     priority_queue<int>que; 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=n; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[cnt--]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     if ( cnt>0 ) { 29         printf("-1\n"); 30         return; 31  } 32     for ( int i=1;i<=n;i++ ) { 33         pos[ans[i]]=i; 34  } 35     for ( int i=1;i<=n;i++ ) { 36         printf("%d",pos[i]); 37         if ( i==n ) printf("\n"); 38         else printf(" "); 39  } 40 } 41 
42 int main() 43 { 44     int m,i,j,k,x,y,T; 45     scanf("%d",&T); 46     while ( T-- ) { 47         scanf("%d%d",&n,&m); 48         for ( i=1;i<=n;i++ ) G[i].clear(); 49         memset(ind,0,sizeof(ind)); 50         while ( m-- ) { 51             scanf("%d%d",&x,&y); 52  G[y].push_back(x); 53             ind[x]++; 54  } 55  toposort(); 56  } 57     return 0; 58 }
POJ3687

 

4.(POJ3553)http://poj.org/problem?id=3553

题意:有n项工做,每项工做有一个持续时间和截至时间。有m条关系,每条关系(x,y)表示任务x必定要在任务y前进行。对于任务j来讲当前的完成时间记作cj,现使得全部任务的max[cj-dj,0]最小,求任务进行的顺序

分析:由偏序获得全序的条件是max[cj-dj,0]最小,那么咱们能够将优先队列中的顺序按照d从小到大进行排列。假设当前的时间为now,当前最小的d对应的任务为i,持续时间为pi,截至时间为di,此时有差值value1=abs(now+pi-di)。若此时不进行任务i,而进行其余任务j,下次再进行任务i对于任务i来讲value2=abs(now+pj+pi-di)必定是比value1要更大的。全部对于当前的局面来讲每次取di最小的能够获得最优的答案

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 #include<cmath>
 7 using namespace std;  8 const int maxn=50010;  9 struct node{ 10     int p; 11     int d; 12     int id; 13     node(int _p=0,int _d=0,int _id=0):p(_p),d(_d),id(_id) {} 14     bool operator < (const node &r)const
15  { 16         return d>r.d; 17  } 18 }arr[maxn]; 19 vector<int>G[maxn]; 20 int ans[maxn],ind[maxn],n; 21 
22 void toposort() 23 { 24     int num,now; 25     num=now=0; 26     priority_queue<node>que; 27     while ( !que.empty() ) que.pop(); 28     for ( int i=1;i<=n;i++ ) { 29         if ( ind[i]==0 ) que.push(node(arr[i].p,arr[i].d,arr[i].id)); 30  } 31     int cnt=0; 32     while ( !que.empty() ) { 33         node tmp=que.top(); 34  que.pop(); 35         int u=tmp.id; 36         now+=arr[u].p; 37         num=max(num,abs(now-arr[u].p)); 38         ans[++cnt]=u; 39         for ( int i=0;i<G[u].size();i++ ) { 40             int v=G[u][i]; 41             ind[v]--; 42             if ( ind[v]==0 ) que.push(node(arr[v].p,arr[v].d,v)); 43  } 44  } 45     for ( int i=1;i<=n;i++ ) { 46         printf("%d\n",ans[i]); 47  } 48 } 49 
50 int main() 51 { 52     int m,i,j,k,x,y; 53     while ( scanf("%d",&n)!=EOF ) { 54         for ( i=1;i<=n;i++ ) G[i].clear(); 55         memset(ind,0,sizeof(ind)); 56         for ( i=1;i<=n;i++ ) { 57             scanf("%d%d",&arr[i].p,&arr[i].d); 58             arr[i].id=i; 59  } 60         scanf("%d",&m); 61         while ( m-- ) { 62             scanf("%d%d",&x,&y); 63  G[x].push_back(y); 64             ind[y]++; 65  } 66  toposort(); 67  } 68     return 0; 69 }
POJ3553

 

5.(POJ2762)http://poj.org/problem?id=2762

题意:给定的图中是否知足对于任意两点(u,v),总有u到v或者v到u

分析:强连通份量。先缩点,而后判断出入度为1的点是否都只有一个.由于当且仅当图为一条链时才知足条件,若是出现分叉则必定不知足条件。

作法2:先缩点再进行toposort,当每次弹出队列中最前面的元素时进行判断队列中是否还有其余元素,若是有则不成立。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=1050;  8 const int maxm=15000;  9 struct edge{  10     int to,nxt;  11 }edge[maxm];  12 int head[maxn],tot;  13 int low[maxn],dfn[maxn],stack[maxn],belong[maxn];  14 int index,top;  15 int scc;  16 bool vis[maxn];  17 int num[maxn];  18 vector<int>G[maxn];  19 int ans[maxn],ind[maxn],n,out[maxn];  20 
 21 void addedge(int u,int v)  22 {  23     edge[tot].to=v;  24     edge[tot].nxt=head[u];  25     head[u]=tot++;  26 }  27 
 28 void tarjan(int u)  29 {  30     int v;  31     low[u]=dfn[u]=++index;  32     stack[top++]=u;  33     vis[u]=true;  34     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {  35         v=edge[i].to;  36         if ( !dfn[v] ) {  37  tarjan(v);  38             low[u]=min(low[u],low[v]);  39  }  40         else if ( vis[v] ) low[u]=min(low[u],dfn[v]);  41  }  42     if ( low[u]==dfn[u] ) {  43         scc++;  44         do {  45             v=stack[--top];  46             vis[v]=false;  47             belong[v]=scc;  48             num[scc]++;  49  }  50         while ( v!=u );  51  }  52 }  53 
 54 void solve(int N)  55 {  56     memset(dfn,0,sizeof(dfn));  57     memset(vis,false,sizeof(vis));  58     memset(num,0,sizeof(num));  59     index=scc=top=0;  60     for ( int i=1;i<=N;i++ ) {  61         if ( !dfn[i] ) tarjan(i);  62  }  63 }  64 
 65 void init()  66 {  67     tot=0;  68     memset(head,-1,sizeof(head));  69 }  70 
 71 int main()  72 {  73     int m,i,j,k,x,y,z,T;  74     scanf("%d",&T);  75     while ( T-- ) {  76         scanf("%d%d",&n,&m);  77  init();  78         for ( i=0;i<m;i++ ) {  79             scanf("%d%d",&x,&y);  80  addedge(x,y);  81  }  82  solve(n);  83         for ( i=1;i<=scc;i++ ) G[i].clear();  84         memset(ind,0,sizeof(ind));  85         memset(out,0,sizeof(out));  86         for ( i=1;i<=n;i++ ) {  87             for ( j=head[i];j!=-1;j=edge[j].nxt ) {  88                 int v=edge[j].to;  89                 if ( belong[i]!=belong[v] ) {  90                     ind[belong[v]]++;  91                     out[belong[i]]++;  92  }  93  }  94  }  95         int now1,now2;  96         now1=now2=0;  97         for ( i=1;i<=scc;i++ ) {  98             if ( ind[i]==0 ) now1++;  99             if ( out[i]==0 ) now2++; 100  } 101         if ( now1==1 && now2==1 ) printf("Yes\n"); 102         else printf("No\n"); 103  } 104     return 0; 105 }
POJ2762

 

6.(HDOJ1811)http://acm.hdu.edu.cn/showproblem.php?pid=1811

分析:并查集+toposort。首先并查集的做用在于对于那些rating相等的人他们之间的排名必定是肯定的,这时候能够考虑“缩点”,将那些rating相等的人缩成一个点,此时要注意不能边缩点边建图,而是须要先所有缩点完成后再建图,不然建图会有误。同时在整个toposort的过程当中,对象的编号是并查集完成后的编号,对象的数目是缩点后的数目。对于三种状况的断定:当出现环时则为矛盾(此时cnt<num)。判断信息是否完备的条件同POJ2762,当只有一条链时才能说明信息完备,此时判断每一个点弹出队列后是否还有元素在队列当中。其余状况输出OK。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #include<vector>
 6 using namespace std;  7 const int maxn=100005;  8 vector<int>G[maxn];  9 int n,ind[maxn],cnt,F[maxn],sum; 10 struct node{ 11     int a; 12     int b; 13     char c; 14 }arr[maxn*2]; 15 
16 int find(int x) 17 { 18     if ( F[x]==-1 ) return x; 19     return F[x]=find(F[x]); 20 } 21 
22 void merge(int x,int y) 23 { 24     int dx,dy; 25     dx=find(x); 26     dy=find(y); 27     if ( dx!=dy ) F[dx]=dy; 28 } 29 
30 void toposort() 31 { 32     queue<int>que; 33     bool flag=false; 34     cnt=0; 35     for ( int i=0;i<n;i++ ) { 36         if ( ind[i]==0 && F[i]==-1 ) que.push(i); //F[i]==-1的判断条件不能遗漏 
37  } 38     while ( !que.empty() ) { 39         
40         int tmp=que.front(); 41  que.pop(); 42         if ( !que.empty() ) flag=true; //判断是否为直链 
43         cnt++; 44         for ( int i=0;i<G[tmp].size();i++ ) { 45             ind[G[tmp][i]]--; 46             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 47  } 48  } 49     if ( cnt<sum ) printf("CONFLICT\n"); 50     else if ( flag ) printf("UNCERTAIN\n"); 51     else printf("OK\n"); 52 } 53 
54 int main() 55 { 56     int m,i,j,k,fy,fx; 57     char s; 58     while ( scanf("%d%d",&n,&m)!=EOF ) { 59         memset(ind,0,sizeof(ind)); 60         memset(F,-1,sizeof(F)); 61         for ( i=0;i<n;i++ ) G[i].clear(); 62         for ( i=1;i<=m;i++) { 63             scanf("%d %c %d",&arr[i].a,&arr[i].c,&arr[i].b); 64             if ( arr[i].c=='=' ) merge(arr[i].a,arr[i].b); 65  } 66         for ( i=1;i<=m;i++ ) { 67             fx=find(arr[i].a); 68             fy=find(arr[i].b); 69             if ( arr[i].c=='=' ) continue; 70             else if ( arr[i].c=='>' ) { 71  G[fx].push_back(fy); 72                 ind[fy]++; 73  } 74             else if ( arr[i].c=='<' ) { 75  G[fy].push_back(fx); 76                 ind[fx]++; 77  } 78  } 79         sum=0; 80         for ( i=0;i<n;i++ ) { 81             if ( F[i]==-1 ) sum++; 82  } 83  toposort(); 84  } 85     return 0; 86 }
HDOJ1811

 

7.(HDOJ3357)http://acm.hdu.edu.cn/showproblem.php?pid=3357

题意:有n个公司和m笔交易,每笔交易(x,y)表示x公司买y公式的股份,当一个公司试图购买其父公司的股份时交易便会被中止,求中止的交易数

分析:原本应该每次加一条边而后进行一次拓扑排序判断有无环,可是复杂度太大。因此才用floyd来判环。具体作法是每一个输入(x,y),先判断y是否为x的父公司(即y购买过x的股份),同时须要判断x是否等于y(容易遗漏)。若不是则经过floyd更新一次,可是每次floyd不能进行三层循环。对于添加的边(x-y)来讲能够更新(i-x-y),(x-y-j),(i-x-y-j)三种边,这时候能够用floyd两层循环搞定(最外层k只能为x/y)。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=250;  6 bool d[maxn][maxn];  7 int n;  8 
 9 void floyd(int x,int y) 10 { 11     int i,j,k; 12     for ( i=1;i<=n;i++ ) { 13         if ( !d[i][x] ) continue; 14         for ( j=1;j<=n;j++ ) { 15             if ( d[i][j] || !d[x][j] ) continue; 16             d[i][j]=true; 17  } 18  } 19     for ( i=1;i<=n;i++ ) { 20         if ( !d[i][y] ) continue; 21         for ( j=1;j<=n;j++ ) { 22             if ( d[i][j] || !d[y][j] ) continue; 23             d[i][j]=true; 24  } 25  } 26 } 27 
28 int main() 29 { 30     int i,j,k,x,y,z,m,h=0,ans; 31     while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) { 32         memset(d,false,sizeof(d)); 33         ans=0; 34         for ( i=1;i<=m;i++ ) { 35             scanf("%d%d",&x,&y); 36             if ( d[x][y] ) continue; 37             if ( d[y][x] || x==y ) { 38                 ans++; 39                 continue; 40  } 41             d[x][y]=true; 42  floyd(x,y); 43  } 44         printf("%d. %d\n",++h,ans); 45  } 46     return 0; 47 }
HDOJ3357(1)
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=250;  6 bool d[maxn][maxn];  7 int n;  8 
 9 void floyd(int x,int y) 10 { 11     int i,j,k; 12     for ( i=1;i<=n;i++ ) { 13         if ( d[i][x] ) d[i][y]=true; 14         if ( d[y][i] ) d[x][i]=true; 15  } 16     for ( i=1;i<=n;i++ ) { 17         if ( !d[i][x] ) continue; 18         for ( j=1;j<=n;j++ ) { 19             if ( !d[y][j] || d[i][j] ) continue; 20             d[i][j]=true; 21  } 22  } 23 } 24 
25 int main() 26 { 27     int i,j,k,x,y,z,m,h=0,ans; 28     while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) { 29         memset(d,false,sizeof(d)); 30         ans=0; 31         for ( i=1;i<=m;i++ ) { 32             scanf("%d%d",&x,&y); 33             if ( d[y][x] || x==y ) { 34                 ans++; 35                 continue; 36  } 37             if ( d[x][y] ) continue; 38             d[x][y]=true; 39  floyd(x,y); 40  } 41         printf("%d. %d\n",++h,ans); 42  } 43     return 0; 44 }
HDOJ3357(2)
相关文章
相关标签/搜索