这道题,感觉不是很难,分析清楚之后非常简单。(标签都不知道怎么加)
读完题首先想到了分割点一定是必经点的一种特殊情况,如果分割点不是必经点的话,那么它就不能把这个图分成两半(存在不经过它的边沟通两半)
然后先做比较简单的必经点。想到了割点,但是数据规模太小了,所以不用那么复杂,直接暴力枚举尝试把除起点终点之外的所有点全部删掉,判断图是否连通就可以了。
在必经点的基础上做分割点。
删掉一个点之后,从$0$号点出发标记所有能够遍历到的点,再从被删掉的那个点出发,如果碰到了之前遍历过的点就说明这个点不是分割点。
要注意一个特殊情况:如果这个节点有自环,那么这个节点就不能当做分割点。(自环的那条边为两部分的公共边)(代码里写得很丑,现在想来直接特判一下不就可以了吗)
实现不是很难,广搜和深搜都可以。
(代码里编号好像忘了排序,数据好水啊)
1 //nice 2 /* 3 ID: Starry21 4 LANG: C++ 5 TASK: race3 6 */ 7 #include<cstdio> 8 #include<algorithm> 9 #include<vector> 10 #include<cstring> 11 #include<queue> 12 using namespace std; 13 #define N 55 14 #define ll long long 15 #define INF 0x3f3f3f3f 16 int n; 17 vector<int>G[N],ans1,ans2; 18 int vis[N]; 19 queue<int>Q; 20 int main() 21 { 22 //freopen("race3.in","r",stdin); 23 //freopen("race3.out","w",stdout); 24 while(1) 25 { 26 int x; 27 while(scanf("%d",&x)!=EOF) 28 { 29 if(x==-2||x==-1) break; 30 G[n].push_back(x); 31 } 32 if(x==-1) break; 33 n++; 34 } 35 n--; 36 //printf("%d\n",n); 37 /*for(int i=0;i<=n;i++) 38 { 39 for(int j=0;j<G[i].size();j++) 40 printf("%d ",G[i][j]); 41 puts(""); 42 }*/ 43 for(int s=1;s<=n-1;s++)//0是起点 n是终点 枚举必经点 44 { 45 memset(vis,0,sizeof(vis)); 46 while(!Q.empty()) Q.pop(); 47 Q.push(0); 48 vis[0]=1; 49 while(!Q.empty()) 50 { 51 int u=Q.front();Q.pop(); 52 for(int i=0;i<G[u].size();i++) 53 { 54 int v=G[u][i]; 55 if(vis[v]) continue; 56 vis[v]=1;//56 57行顺序 防自环 57 if(v==s) continue; 58 Q.push(v); 59 } 60 } 61 if(vis[n]) continue; 62 //vis[i]=1 是从0出发不经过s能够到达的点 63 ans1.push_back(s); 64 bool f=0; 65 while(!Q.empty()) Q.pop(); 66 Q.push(s); 67 //这里vis[s]不赋值 防自环 68 while(!Q.empty()) 69 { 70 int u=Q.front();Q.pop(); 71 for(int i=0;i<G[u].size();i++) 72 { 73 int v=G[u][i]; 74 if(vis[v]==2) continue; 75 if(v==s) continue;//vis[s]没有赋值2 76 if(vis[v]==1)//访问到了从s也能到的点 77 { 78 f=1; 79 break; 80 } 81 vis[v]=2; 82 Q.push(v); 83 } 84 if(f) break; 85 } 86 if(!f) ans2.push_back(s); 87 } 88 printf("%d",ans1.size()); 89 for(int i=0;i<ans1.size();i++) 90 printf(" %d",ans1[i]); 91 puts(""); 92 printf("%d",ans2.size()); 93 for(int i=0;i<ans2.size();i++) 94 printf(" %d",ans2[i]); 95 puts(""); 96 } 97 /* 98 注意自环的情况 99 比如: 100 1 -2 101 2 1 -2 102 3 0 -2 103 3 4 -2 104 5 0 -2 105 7 6 -2 106 7 -2 107 8 -2 108 -2 109 -1 110 中的1号点 111 */