桥和割点例题+讲解:hihocoder1183 http://hihocoder.com/problemset/problem/1183

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 #include<set>
6 using namespace std;
7 const int maxn=1005;
8 const int maxm=200010;
9 struct edge{
10 int to,nxt;
11 bool cut;
12 }edge[maxm*2];
13 int head[maxn],tot;
14 int low[maxn],dfn[maxn];
15 int index,n,bridge;
16 set<int>st;
17 bool cut[maxn];
18
19 void addedge(int u,int v)
20 {
21 edge[tot].to=v;
22 edge[tot].nxt=head[u];
23 edge[tot].cut=false;
24 head[u]=tot++;
25 }
26
27 void tarjan(int u,int pre)
28 {
29 low[u]=dfn[u]=++index;
30 int son=0;
31 for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
32 int v=edge[i].to;
33 if ( v==pre ) continue;
34 if ( !dfn[v] ) {
35 son++;
36 tarjan(v,u);
37 low[u]=min(low[u],low[v]);
38 if ( low[v]>dfn[u] ) {
39 bridge++;
40 edge[i].cut=true;
41 edge[i^1].cut=true;
42 }
43 if ( low[v]>=dfn[u] && u!=pre ) {
44 st.insert(u);
45 cut[u]=true;
46 }
47 }
48 else if ( low[u]>dfn[v] ) low[u]=dfn[v];
49 }
50 if ( u==pre && son>1 ) {
51 cut[u]=true;
52 st.insert(u);
53 }
54 }
55
56 void solve()
57 {
58 memset(low,0,sizeof(low));
59 memset(dfn,0,sizeof(dfn));
60 memset(cut,false,sizeof(cut));
61 index=bridge=0;
62 st.clear();
63 for ( int i=1;i<=n;i++ ) {
64 if ( !dfn[i] ) tarjan(i,i);
65 }
66 set<int>::iterator it;
67 if ( st.size()==0 ) printf("Null\n");
68 else {
69 for ( it=st.begin();it!=st.end();it++ ) {
70 if ( it!=st.begin() ) printf(" ");
71 printf("%d",*it);
72 }
73 printf("\n");
74 }
75 vector<pair<int,int> >ans;
76 for ( int i=1;i<=n;i++ ) {
77 for ( int j=head[i];j!=-1;j=edge[j].nxt ) {
78 if ( edge[j].cut && edge[j].to>i ) ans.push_back(make_pair(i,edge[j].to));
79 }
80 }
81 sort(ans.begin(),ans.end());
82 for ( int i=0;i<ans.size();i++ ) {
83 printf("%d %d\n",ans[i].first,ans[i].second);
84 }
85 }
86
87 void init()
88 {
89 tot=0;
90 memset(head,-1,sizeof(head));
91 }
92
93 int main()
94 {
95 int m,i,j,k,x,y,z;
96 while ( scanf("%d%d",&n,&m)!=EOF ) {
97 init();
98 while ( m-- ) {
99 scanf("%d%d",&x,&y);
100 addedge(x,y);
101 addedge(y,x);
102 }
103 solve();
104 }
105 }
边双连通模板

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 using namespace std;
6 const int maxn=1005;
7 const int maxm=200010;
8 struct edge{
9 int to,nxt;
10 bool cut;
11 }edge[maxm*2];
12 int head[maxn],tot,n;
13 int index,ebc_cnt,bridge;
14 int dfn[maxn],low[maxn];
15
16 void addedge(int u,int v)
17 {
18 edge[tot].to=v;
19 edge[tot].nxt=head[u];
20 edge[tot].cut=false;
21 head[u]=tot++;
22 }
23
24 void tarjan(int u,int pre)
25 {
26 low[u]=dfn[u]=++index;
27 for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
28 int v=edge[i].to;
29 if ( v==pre ) continue;
30 if ( !dfn[v] ) {
31 tarjan(v,u);
32 low[u]=min(low[u],low[v]);
33 if ( low[v]>dfn[u] ) {
34 bridge++;
35 edge[i].cut=true;
36 edge[i^1].cut=true;
37 }
38 }
39 else if ( low[u]>dfn[v] ) low[u]=dfn[v];
40 }
41 }
42
43 void solve()
44 {
45 memset(low,0,sizeof(low));
46 memset(dfn,0,sizeof(dfn));
47 index=bridge=0;
48 for ( int i=1;i<=n;i++ ) {
49 if ( !dfn[i] ) tarjan(i,i);
50 }
51 }
52
53 void init()
54 {
55 tot=0;
56 memset(head,-1,sizeof(head));
57 }
点双连通模板

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<stack>
5 #include<vector>
6 using namespace std;
7 const int maxn=1005;
8 const int maxm=200010;
9 struct edge{
10 int to,nxt;
11 }edge[maxm*2];
12 struct Edge{
13 int u,v;
14 Edge(int _u=0,int _v=0):u(_u),v(_v) {}
15 };
16 int dfn[maxn],low[maxn];
17 int head[maxn],tot;
18 int index,n;
19 bool cut[maxn];
20 int bcc_cnt,bccno[maxn];
21 vector<int>bcc[maxn];
22 stack<Edge>s;
23
24 void addedge(int u,int v)
25 {
26 edge[tot].to=v;
27 edge[tot].nxt=head[u];
28 head[u]=tot++;
29 }
30
31 void tarjan(int u,int pre)
32 {
33 low[u]=dfn[u]=++index;
34 int son=0;
35 for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
36 int v=edge[i].to;
37 if ( v==pre ) continue;
38 Edge e(u,v);
39 if ( !dfn[v] ) {
40 s.push(e);
41 son++;
42 tarjan(v,u);
43 low[u]=min(low[u],low[v]);
44 if ( low[v]>=dfn[u] ) {
45 cut[u]=true;
46 bcc_cnt++;
47 bcc[bcc_cnt].clear();
48 for (;;)
49 {
50 Edge x=s.top();
51 s.pop();
52 if ( bccno[x.u]!=bcc_cnt ) {
53 bcc[bcc_cnt].push_back(x.u);
54 bccno[x.u]=bcc_cnt;
55 }
56 if ( bccno[x.v]!=bcc_cnt ) {
57 bcc[bcc_cnt].push_back(x.v);
58 bccno[x.v]=bcc_cnt;
59 }
60 if ( x.u==u && x.v==v ) break;
61 }
62 }
63 }
64 else if ( dfn[v]<dfn[u] && v!=pre ) {
65 s.push(e);
66 low[u]=min(low[u],dfn[v]);
67 }
68 }
69 if ( u==pre && son==1 ) cut[u]=false;
70 }
71
72 void solve()
73 {
74 memset(dfn,0,sizeof(dfn));
75 memset(low,0,sizeof(low));
76 memset(cut,false,sizeof(cut));
77 index=bcc_cnt=0;
78 while ( !s.empty() ) s.pop();
79 for ( int i=1;i<=n;i++ ) {
80 if ( !dfn[i] ) tarjan(i,i);
81 }
82 }
83
84 void init()
85 {
86 tot=0;
87 memset(head,-1,sizeof(head));
88 }
1.(POJ2117)http://poj.org/problem?id=2117 (求连通块数量)
题意:去掉一个点使得有更多的连通块,求最多有多少连通块
分析:添加数组add_block[],当u为割点时则add_block[u]++,最后逐一枚举要去掉的点。特别注意对于数根来说add_block[u]=son-1

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 #include<set>
6 using namespace std;
7 const int maxn=20005;
8 const int maxm=100010;
9 struct edge{
10 int to,nxt;
11 bool cut;
12 }edge[maxm*3];
13 int head[maxn],tot;
14 int low[maxn],dfn[maxn];
15 int index,n,bridge;
16 int add_block[maxn];
17 set<int>st;
18 bool cut[maxn];
19
20 void addedge(int u,int v)
21 {
22 edge[tot].to=v;
23 edge[tot].nxt=head[u];
24 edge[tot].cut=false;
25 head[u]=tot++;
26 }
27
28 void tarjan(int u,int pre)
29 {
30 low[u]=dfn[u]=++index;
31 int son=0;
32 for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
33 int v=edge[i].to;
34 if ( v==pre ) continue;
35 if ( !dfn[v] ) {
36 son++;
37 tarjan(v,u);
38 low[u]=min(low[u],low[v]);
39 if ( low[v]>dfn[u] ) {
40 bridge++;
41 edge[i].cut=true;
42 edge[i^1].cut=true;
43 }
44 if ( u!=pre && low[v]>=dfn[u] ) {
45 st.insert(u);
46 cut[u]=true;
47 add_block[u]++;
48 }
49 }
50 else if ( low[u]>dfn[v] ) low[u]=dfn[v];
51 }
52 if ( u==pre && son>1 ) {
53 cut[u]=true;
54 st.insert(u);
55 }
56 if ( u==pre ) add_block[u]=son-1;
57 }
58
59 void solve()
60 {
61 memset(low,0,sizeof(low));
62 memset(dfn,0,sizeof(dfn));
63 memset(cut,false,sizeof(cut));
64 memset(add_block,0,sizeof(add_block));
65 int cnt,ans;
66 index=bridge=cnt=ans=0;
67 for ( int i=1;i<=n;i++ ) {
68 if ( !dfn[i] ) {
69 tarjan(i,i);
70 cnt++;
71 }
72 }
73 for ( int i=1;i<=n;i++ ) ans=max(ans,cnt+add_block[i]);
74 printf("%d\n",ans);
75 }
76
77 void init()
78 {
79 tot=0;
80 memset(head,-1,sizeof(head));
81 st.clear();
82 }
83
84 int main()
85 {
86 int m,i,j,k,x,y,z;
87 while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) {
88 init();
89 while ( m-- ) {
90 scanf("%d%d",&x,&y);
91 x++;y++;
92 addedge(x,y);
93 addedge(y,x);
94 }
95 solve();
96 }
97 }
2.(POJ3117)http://poj.org/problem?id=3177 (构造边双连通)
题意:求添加多少条边后在图中的任意两点都有两条边不重复的路径
分析:边双连通,利用强连通分量中的写法,把每个点对应的缩点后的点标记下来。最后构建新图(即进行缩点,边只存在原先为桥的边)记录入度(或者出度,选择一个即可),最后入度为1的点即为叶子节点,对于一棵树想要使其变成边双连通,所加的边数=(叶子节点的个数+1)/2

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 using namespace std;
6 const int maxn=1005;
7 const int maxm=200010;
8 struct edge{
9 int to,nxt;
10 bool cut;
11 }edge[maxm*2];
12 int head[maxn],tot,n;
13 int index,ebc_cnt,bridge,block,top;
14 int dfn[maxn],low[maxn],belong[maxn],stack[maxn],du[maxn];
15 bool vis[maxn];
16
17 void addedge(int u,int v)
18 {
19 edge[tot].to=v;
20 edge[tot].nxt=head[u];
21 edge[tot].cut=false;
22 head[u]=tot++;
23 }
24
25 void tarjan(int u,int pre)
26 {
27 low[u]=dfn[u]=++index;
28 stack[top++]=u;
29 vis[u]=true;
30 for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
31 int v=edge[i].to;
32 if ( v==pre ) continue;
33 if ( !dfn[v] ) {
34 tarjan(v,u);
35 low[u]=min(low[u],low[v]);
36 if ( low[v]>dfn[u] ) {
37 bridge++;
38 edge[i].cut=true;
39 edge[i^1].cut=true;
40 }
41 }
42 else if ( low[u]>dfn[v] && vis[v] ) low[u]=dfn[v];
43 }
44 if ( low[u]==dfn[u] ) {
45 block++;
46 int v;
47 do
48 {
49 v=stack[--top];
50 vis[v]=true;
51 belong[v]=block;
52 }
53 while ( v!=u );
54 }
55 }
56
57 void solve()
58 {
59 memset(low,0,sizeof(low));
60 memset(dfn,0,sizeof(dfn));
61 memset(vis,false,sizeof(vis));
62 index=bridge=block=top=0;
63 for ( int i=1;i<=n;i++ ) {
64 if ( !dfn[i] ) tarjan(i,i);
65 }
66 memset(du,0,sizeof(du));
67 for ( int i=1;i<=n;i++ ) {
68 for ( int j=head[i];j!=-1;j=edge[j].nxt ) {
69 if ( edge[j].cut ) {
70 du[belong[i]]++;
71 }
72 }
73 }
74 int cnt=0;
75 for ( int i=1;i<=block;i++ ) {
76 if ( du[i]==1 ) cnt++;
77 }
78 printf("%d\n",(cnt+1)/2);
79 }
80
81 void init()
82 {
83 tot=0;
84 memset(head,-1,sizeof(head));
85 }
86
87 int main()
88 {
89 int m,i,j,k,x,y,z;
90 while ( scanf("%d%d",&n,&m)!=EOF ) {
91 init();
92 for ( i=1;i<=m;i++ ) {
93 scanf("%d%d",&x,&y);
94 addedge(x,y);
95 addedge(y,x);
96 }
97 solve();
98 }
99 return 0;
100 }
3.(HDOJ2242)http://acm.hdu.edu.cn/showproblem.php?pid=2242
分析:边双连通+搜索。首先分成3类情况,对于初始时连通块的数量>2或者连通块为1但不存在桥直接输出impossible。而对于连通块本身为2的图来说不用切断如何一条管道即可将整个图分成两部分。最后仅仅需要对连通块数量为1,同时桥的数量>0的图进行考虑即可。给每个点标号标记它们属于第几个边强连通分量,然后构建新图。最后对新图进行搜索,不断更新答案.同时注意存在重flag解决存在重边的问题。

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 #include<cmath>
6 using namespace std;
7 const int maxn=10005;
8 const int maxm=20010;
9 struct edge{
10 int to,nxt;
11 bool cut;
12 }edge[maxm*2];
13 int head[maxn],tot,n;
14 int index,ebc_cnt,bridge,block,top,ans,sum;
15 int dfn[maxn],low[maxn],belong[maxn],stack[maxn],num[maxn],num_[maxn];
16 bool vis[maxn];
17 vector<int>G[maxn];
18
19 void addedge(int u,int v)
20 {
21 edge[tot].to=v;
22 edge[tot].nxt=head[u];
23 edge[tot].cut=false;
24 head[u]=tot++;
25 }
26
27 void addedge_(int u,int v)
28 {
29 G[u].push_back(v);
30 }
31
32 void tarjan(int u,int pre)
33 {
34 low[u]=dfn[u]=++index;
35 stack[top++]=u;
36 vis[u]=true;
37 bool flag=false;
38 for ( int i=head[u];i!=-1;i=edge[i].nxt ) {
39 int v=edge[i].to;
40 if ( v==pre && !flag ) {
41 flag=true;
42 continue;
43 }
44 if ( !dfn[v] ) {
45 tarjan(v,u);
46 low[u]=min(low[u],low[v]);
47 if ( low[v]>dfn[u] ) {
48 bridge++;
49 edge[i].cut=true;
50 edge[i^1].cut=true;
51 }
52 }
53 else if ( low[u]>dfn[v] && vis[v] ) low[u]=dfn[v];
54 }
55 if ( low[u]==dfn[u] ) {
56 block++;
57 int v;
58 do
59 {
60 v=stack[--top];
61 vis[v]=true;
62 belong[v]=block;
63 }
64 while ( v!=u );
65 }
66 }
67
68 int dfs(int u,int pre)
69 {
70 int now=num_[u];
71 for ( int i=0;i<G[u].size();i++ ) {
72 int v=G[u][i];
73 if ( v!=pre ) now+=dfs(v,u);
74 }
75 ans=min(ans,abs(sum-2*now));
76 return now;
77 }
78
79 void solve()
80 {
81 memset(low,0,sizeof(low));
82 memset(dfn,0,sizeof(dfn));
83 memset(vis,false,sizeof(vis));
84 int cnt,now;
85 index=bridge=block=top=now=cnt=0;
86 for ( int i=1;i<=n;i++ ) {
87 if ( !dfn[i] ) {
88 tarjan(i,i);
89 cnt++;
90 }
91 if ( i==1 ) {
92 for ( int j=1;j<=n;j++ ) {
93 if ( dfn[j] ) now+=num[j];
94 }
95 }
96 }
97 memset(num_,0,sizeof(num_));
98 for ( int i=1;i<=n;i++ ) num_[belong[i]]+=num[i];
99 if ( cnt>2 || bridge==0 ) {
100 printf("impossible\n");
101 return;
102 }
103 else if ( cnt==2 ) {
104 printf("%d\n",abs(sum-2*now));
105 return;
106 }
107 for ( int i=1;i<=block;i++ ) G[i].clear();
108 for ( int i=1;i<=n;i++ ) {
109 for ( int j=head[i];j!=-1;j=edge[j].nxt ) {
110 int v=edge[j].to;
111 if ( edge[j].cut ) {
112 int x=belong[i];
113 int y=belong[v];
114 addedge_(x,y);
115 }
116 }
117 }
118 ans=sum;
119 dfs(1,1);
120 printf("%d\n",ans);
121 }
122
123 void init()
124 {
125 tot=0;
126 memset(head,-1,sizeof(head));
127 }
128
129 int main()
130 {
131 int m,i,j,k,x,y,z;
132 while ( scanf("%d%d",&n,&m)!=EOF ) {
133 init();
134 sum=0;
135 for ( i=1;i<=n;i++ ) {
136 scanf("%d",&num[i]);
137 sum+=num[i];
138 }
139 for ( i=1;i<=m;i++ ) {
140 scanf("%d%d",&x,&y);
141 x++;y++;
142 addedge(x,y);
143 addedge(y,x);
144 }
145 solve();
146 }
147 return 0;
148 }
来源:https://www.cnblogs.com/HDUjackyan/p/8822773.html
