题目:传送门
题意:给你一个无向图,你需要找出里面的桥,并把所有桥按字典序输出
这一道题就是用无向图求桥的模板就可以了。
我一直错就是因为我在输入路径的时候少考虑一点
错误代码+原因:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int maxn=1005; 8 struct shudui 9 { 10 int x,y; 11 bool operator < (const shudui t)const 12 { 13 if(x==t.x) 14 return y>t.y; 15 else return x>t.x; 16 } 17 }str1; 18 priority_queue<shudui>r; 19 int w[maxn][maxn]; 20 int cnt,head[maxn],n,dfn[maxn],low[maxn],num,qua,root,iscut[maxn]; 21 struct edge 22 { 23 int u,v,next; 24 }e[maxn*maxn]; 25 void add_edge(int x,int y) 26 { 27 e[cnt].u=x; 28 e[cnt].v=y; 29 e[cnt].next=head[x]; 30 head[x]=cnt++; 31 } 32 void tarjan(int x,int fx) 33 { 34 dfn[x]=low[x]=++num; 35 for(int i=head[x];i;i=e[i].next) 36 { 37 int to=e[i].v; 38 if(!dfn[to]) 39 { 40 tarjan(to,i); 41 low[x]=min(low[x],low[to]); 42 if(low[to]>dfn[x]) 43 { //因为我把双向边放在了一起,即1->2放在了cnt为2的地方,2->1放在了cnt为3的地方。 44 //那么就可以通过2^1=3找到另一个反方向的边,或者3^1=2.那么这个双向边就被标记成了桥 45 iscut[i]=iscut[i^1]=1; 46 } 47 } 48 else if(i!=(fx^1)) 49 low[x]=min(dfn[to],low[x]); 50 } 51 } 52 int main() 53 { 54 while(~scanf("%d",&n)) 55 { 56 if(n==0) 57 { 58 printf("0 critical links "); 59 continue; 60 } 61 cnt=2; 62 num=qua=0; 63 memset(w,0,sizeof(w)); 64 memset(iscut,0,sizeof(iscut)); 65 memset(head,0,sizeof(head)); 66 memset(dfn,0,sizeof(dfn)); 67 memset(low,0,sizeof(low)); 68 for(int i=1;i<=n;++i) 69 { 70 int x,y,sum; 71 char ch; 72 scanf("%d %c%d%c",&x,&ch,&sum,&ch); 73 x+=1; 74 while(sum--) 75 { 76 scanf("%d",&y); 77 y+=1; 78 if(!w[x][y]) //我原本是想要添加就添加一对互反方向的边(即1->2和2->1,因为用这种方式找桥的时 79 //候,你必须保证互反方向的边存在一起,这样可以通过i^1来找到边的另一个方向)。但是我有一点没有考虑到 80 //就是我这样判断的话如果题目给出两条1到2的无向边的时候我的代码就错了。因为我的代码默认 81 //只会给两点之间添加至多一次无向边 82 { 83 add_edge(x,y); 84 add_edge(y,x); 85 w[x][y]=w[y][x]=1; 86 } 87 } 88 } 89 90 for(int i=1;i<=n;++i) 91 { 92 if(!dfn[i]) 93 { 94 tarjan(i,0); 95 } 96 } 97 int ans=0; 98 for(int i=2;i<cnt;i+=2) 99 { 100 if(iscut[i]) 101 { 102 str1.x=min(e[i^1].v-1,e[i].v-1); 103 str1.y=max(e[i^1].v-1,e[i].v-1); 104 r.push(str1); 105 ans++; 106 } 107 108 } 109 printf("%d critical links ",ans); 110 while(!r.empty()) 111 { 112 str1=r.top(); 113 r.pop(); 114 printf("%d - %d ",str1.x,str1.y); 115 } 116 printf(" "); 117 } 118 return 0; 119 }
正解代码1:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<map> 7 #include<vector> 8 using namespace std; 9 const int maxn = 1e5+10; 10 const int M=1e5+10; 11 struct node { 12 int v, next; 13 }e[M]; 14 struct shudui 15 { 16 int x,y; 17 bool operator < (const shudui t)const 18 { 19 if(x==t.x) 20 return y>t.y; 21 else return x>t.x; 22 } 23 }str1; 24 priority_queue<shudui>r; 25 map<int,int>w; 26 int head[maxn], cnt; 27 bool iscut[maxn]; 28 int dfn[maxn], low[maxn]; 29 int num,n; 30 inline void add_edge(int xx, int yy) { 31 e[++cnt].next = head[xx]; 32 e[cnt].v = yy; 33 head[xx] = cnt; 34 } 35 36 inline void tarjan(int x, int in_edge) { 37 dfn[x] = low[x] = ++num; 38 for(int i = head[x]; i; i = e[i].next) { 39 int to = e[i].v; 40 if(!dfn[to]) { 41 tarjan(to, i); 42 low[x] = min(low[x], low[to]); 43 if(low[to] > dfn[x]) 44 iscut[i] = iscut[i ^ 1] = true; 45 } 46 else if(i != (in_edge ^ 1)) 47 low[x] = min(low[x], dfn[to]); 48 } 49 } 50 int main() 51 { 52 while(~scanf("%d",&n)) 53 { 54 cnt=1; 55 num=0; 56 memset(iscut,0,sizeof(iscut)); 57 memset(head,0,sizeof(head)); 58 memset(dfn,0,sizeof(dfn)); 59 memset(low,0,sizeof(low)); 60 if(n==0) 61 { 62 printf("0 critical links "); 63 continue; 64 } 65 int u,k,v; 66 for(int i = 1; i <= n; i++) 67 { 68 scanf("%d (%d)",&u,&k); 69 u++; 70 while(k--) 71 { 72 scanf("%d",&v); 73 v++; 74 if(v <= u)continue; 75 add_edge(u,v); 76 add_edge(v,u); 77 } 78 } 79 for(int i=1;i<=n;++i) 80 { 81 if(!dfn[i]) 82 { 83 tarjan(i,0); 84 } 85 } 86 vector<pair<int,int> >ans; 87 int anss=0; 88 for(int i=2;i<cnt;i+=2) 89 { 90 if(iscut[i]) 91 { 92 int xx=min(e[i^1].v-1,e[i].v-1); 93 int yy=max(e[i^1].v-1,e[i].v-1); 94 ans.push_back(make_pair(xx,yy)); 95 anss++; 96 } 97 98 } 99 printf("%d critical links ",anss); 100 sort(ans.begin(),ans.end()); //默认从小到大排序 101 for(int i = 0; i < ans.size(); i++) 102 printf("%d - %d ",ans[i].first,ans[i].second); 103 printf(" "); 104 } 105 return 0; 106 }
正解代码2(kuangbin):
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <map> 6 #include <vector> 7 using namespace std; 8 const int N = 1e4+10; 9 const int M = 1e5+10; 10 struct Edge{ 11 int to,next; 12 bool cut;//是否为桥的标记 13 }edge[M]; 14 int head[N],tot,n; 15 int low[N],dfn[N],Stack[N]; 16 int Index,top; 17 bool Instack[N],cut[N]; 18 int add_block[N];//删除一个点后增加的连通块 19 int bridge; 20 void init(){ 21 memset(head,-1,sizeof(head)); 22 memset(dfn,0,sizeof(dfn)); 23 memset(Instack,false,sizeof(Instack)); 24 memset(add_block,0,sizeof(add_block)); 25 memset(cut,false,sizeof(cut)); 26 Index=top=bridge=tot = 0; 27 } 28 void addedge(int u,int v){ 29 edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut = false; 30 head[u] = tot++; 31 } 32 void Tarjan(int u,int pre){ 33 low[u] = dfn[u] = ++Index; 34 Stack[top++] = u; 35 Instack[u] = true; 36 int son = 0; 37 for(int i = head[u];i != -1;i = edge[i].next){ 38 int v = edge[i].to; 39 if(v == pre)continue; 40 if( !dfn[v] ){ 41 son++; 42 Tarjan(v,u); 43 if(low[u] > low[v])low[u] = low[v]; 44 if(low[v] > dfn[u]){ //一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<low(v) 45 bridge++; 46 edge[i].cut = true; //正反两边都标记为桥 47 edge[i^1].cut = true; 48 } 49 if(u != pre && low[v] >= dfn[u]){ 50 cut[u] = true; //该点为割点 51 add_block[u]++; 52 } 53 } 54 else if( low[u] > dfn[v])low[u] = dfn[v]; 55 } 56 if(u == pre && son > 1)cut[u] = true; //若u为根,且分支数>1,则u割点 57 if(u == pre)add_block[u] = son - 1; 58 Instack[u] = false; 59 top--; 60 } 61 void solve(){ 62 for(int i = 1;i <= n;i++) 63 if( !dfn[i] ) 64 Tarjan(i,i); 65 printf("%d critical links ",bridge); 66 67 vector<pair<int,int> >ans; /*-- 将桥按顺序输出 --*/ 68 for(int u = 1;u <= n;u++) 69 for(int i = head[u];i != -1;i = edge[i].next) 70 if(edge[i].cut && edge[i].to > u){ 71 ans.push_back(make_pair(u,edge[i].to)); 72 } 73 sort(ans.begin(),ans.end()); 74 for(int i = 0;i < ans.size();i++) 75 printf("%d - %d ",ans[i].first-1,ans[i].second-1); 76 printf(" "); 77 } 78 //处理重边 79 /*map<int,int>mapit; 80 inline bool isHash(int u,int v) 81 { 82 if(mapit[u*N+v])return true; 83 if(mapit[v*N+u])return true; 84 mapit[u*N+v] = mapit[v*N+u] = 1; 85 return false; 86 }*/ 87 int main(){ 88 while(scanf("%d",&n) == 1){ 89 init(); 90 int u,k,v; 91 //mapit.clear(); 92 for(int i = 1;i <= n;i++){ 93 scanf("%d (%d)",&u,&k); 94 u++; 95 //这样加边,要保证正边和反边是相邻的,建无向图 96 while(k--){ 97 scanf("%d",&v); 98 v++; 99 if(v <= u)continue; 100 //if(isHash(u,v))continue; 101 addedge(u,v); 102 addedge(v,u); 103 } 104 } 105 solve(); 106 } 107 return 0; 108 }
只求桥板子1:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 100086; 4 struct node { 5 int y, net; 6 }e[maxn << 1]; 7 int lin[maxn], len = 1; 8 bool bridge[maxn << 1]; 9 int dfn[maxn], low[maxn]; 10 int n, m, num; 11 12 inline int read() { 13 int x = 0, y = 1; 14 char ch = getchar(); 15 while(!isdigit(ch)) { 16 if(ch == '-') y = -1; 17 ch = getchar(); 18 } 19 while(isdigit(ch)) { 20 x = (x << 1) + (x << 3) + ch - '0'; 21 ch = getchar(); 22 } 23 return x * y; 24 } 25 26 inline void insert(int xx, int yy) { 27 e[++len].net = lin[xx]; 28 e[len].y = yy; 29 lin[xx] = len; 30 } 31 32 inline void tarjan(int x, int in_edge) { 33 dfn[x] = low[x] = ++num; 34 for(int i = lin[x]; i; i = e[i].net) { 35 int to = e[i].y; 36 if(!dfn[to]) { 37 tarjan(to, i); 38 low[x] = min(low[x], low[to]); 39 if(low[to] > dfn[x]) 40 bridge[i] = bridge[i ^ 1] = true; 41 } 42 else if(i != (in_edge ^ 1)) 43 low[x] = min(low[x], dfn[to]); 44 } 45 } 46 47 int main() { 48 n = read(), m = read(); 49 len = 1; 50 for(int i = 1; i <= m; ++i) { 51 int x, y, z; 52 x = read(), y = read(); 53 insert(x, y); 54 insert(y, x); 55 } 56 for(int i = 1; i <= n; ++i) 57 if(!dfn[i]) tarjan(i, 0); 58 for(int i = 2; i < len; i += 2) 59 if(bridge[i]) 60 cout << e[i ^ 1].y << ' ' << e[i].y << ' '; 61 return 0; 62 }
只求桥板子2:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <map> 6 #include <vector> 7 using namespace std; 8 const int N = 1e4+10; 9 const int M = 1e5+10; 10 struct Edge{ 11 int to,next; 12 bool cut;//是否为桥的标记 13 }edge[M]; 14 int head[N],tot,n; 15 int low[N],dfn[N],Stack[N]; 16 int Index,top; 17 bool Instack[N],cut[N]; 18 int add_block[N];//删除一个点后增加的连通块 19 int bridge; 20 void init(){ 21 memset(head,-1,sizeof(head)); 22 memset(dfn,0,sizeof(dfn)); 23 memset(Instack,false,sizeof(Instack)); 24 memset(add_block,0,sizeof(add_block)); 25 memset(cut,false,sizeof(cut)); 26 Index=top=bridge=tot = 0; 27 } 28 void addedge(int u,int v){ 29 edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut = false; 30 head[u] = tot++; 31 } 32 void Tarjan(int u,int pre){ 33 low[u] = dfn[u] = ++Index; 34 // Stack[top++] = u; 35 // Instack[u] = true; 36 int son = 0; 37 for(int i = head[u];i != -1;i = edge[i].next){ 38 int v = edge[i].to; 39 if(v == pre)continue; 40 if( !dfn[v] ){ 41 son++; 42 Tarjan(v,u); 43 if(low[u] > low[v])low[u] = low[v]; 44 if(low[v] > dfn[u]){ //一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<low(v) 45 bridge++; 46 edge[i].cut = true; //正反两边都标记为桥 47 edge[i^1].cut = true; 48 } 49 // if(u != pre && low[v] >= dfn[u]){ 50 // cut[u] = true; //该点为割点 51 // add_block[u]++; 52 // } 53 } 54 else if( low[u] > dfn[v])low[u] = dfn[v]; 55 } 56 // if(u == pre && son > 1)cut[u] = true; //若u为根,且分支数>1,则u割点 57 // if(u == pre)add_block[u] = son - 1; 58 // Instack[u] = false; 59 // top--; 60 } 61 void solve(){ 62 for(int i = 1;i <= n;i++) 63 if( !dfn[i] ) 64 Tarjan(i,i); 65 printf("%d critical links ",bridge); 66 67 vector<pair<int,int> >ans; /*-- 将桥按顺序输出 --*/ 68 for(int u = 1;u <= n;u++) 69 for(int i = head[u];i != -1;i = edge[i].next) 70 if(edge[i].cut && edge[i].to > u){ 71 ans.push_back(make_pair(u,edge[i].to)); 72 } 73 sort(ans.begin(),ans.end()); 74 for(int i = 0;i < ans.size();i++) 75 printf("%d - %d ",ans[i].first-1,ans[i].second-1); 76 printf(" "); 77 } 78 //处理重边 79 /*map<int,int>mapit; 80 inline bool isHash(int u,int v) 81 { 82 if(mapit[u*N+v])return true; 83 if(mapit[v*N+u])return true; 84 mapit[u*N+v] = mapit[v*N+u] = 1; 85 return false; 86 }*/ 87 int main(){ 88 while(scanf("%d",&n) == 1){ 89 init(); 90 int u,k,v; 91 //mapit.clear(); 92 for(int i = 1;i <= n;i++){ 93 scanf("%d (%d)",&u,&k); 94 u++; 95 //这样加边,要保证正边和反边是相邻的,建无向图 96 while(k--){ 97 scanf("%d",&v); 98 v++; 99 if(v <= u)continue; 100 //if(isHash(u,v))continue; 101 addedge(u,v); 102 addedge(v,u); 103 } 104 } 105 solve(); 106 } 107 return 0; 108 }