POJ1637-Sightseeing tour/HDU-3472-HS BDC-最大流Dinic+判断混合图的欧拉图
Posted ofshk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1637-Sightseeing tour/HDU-3472-HS BDC-最大流Dinic+判断混合图的欧拉图相关的知识,希望对你有一定的参考价值。
前置知识:
混合图:一幅图中既有单向边,又有双向边。
混合图(既有有向边又有无向边的图)中欧拉环、欧拉路径的判定需要用到网络流这个算法!!!
有向图的欧拉回路的条件:所有的节点出度等于入度。
下面这两题基本差不多,但是建边啊、判断欧拉图啊等还是有区别的。
总之最后都是需要判断是否为满流,如果为满流则说明是欧拉回路。
注意:
1、tot初始化为-1,因为在进行反向边的时候通过异或是01、23、45、...这样为一组的。
if(di>0) { e[i].flow-=di; e[i^1].flow+=di; return di; }
2、源点和汇点s和t要搞清楚设置为多少,有些题目设置s=n、t=n+1的时候会造成s->t没有边,从而造成错误。
POJ1637-Sightseeing tour
题意:问给出的混合图中是否存在欧拉回路。
每行数据后面的0代表无向,1代表有向。
AC代码:
1 #include<string.h>
2 #include<iostream>
3 #include<stdio.h>
4 #include<algorithm>
5 #include<queue>
6 #include<vector>
7 #include<map>
8 #include<cmath>
9 using namespace std;
10 #define inf 0x3f3f3f3f
11 const int N=220;
12 typedef long long ll;
13
14 int n,m,s,t,tot;
15 int head[10*N],dep[10*N],cur[10*N],floww;
16 int in[N],out[N];
17
18 struct node
19 {
20 // int u,v,flow;
21 int nextt,v,flow;
22 }e[N*N];
23
24 void add(int u,int v,int flow)
25 {
26 tot++;
27 //nextt[tot]=head[u];
28 e[tot].nextt=head[u];
29 head[u]=tot;
30 // e[tot].u=u;
31 e[tot].v=v;
32 e[tot].flow=flow;
33
34 /* tot++;
35 // nextt[tot]=head[v];
36 e[tot].nextt=head[v];
37 head[v]=tot;
38 //e[tot].u=v;
39 e[tot].v=u;
40 e[tot].flow=0;*/
41 }
42
43 int dfs(int u,int flow)
44 {
45 if(u==t)
46 return flow;
47 for(int &i=cur[u]; i!=-1; i=e[i].nextt) //注意这里的&符号,这样i增加的同时也能改变cur[u]的值,达到记录当前弧的目的
48 {
49 if((dep[e[i].v]==dep[u]+1)&&e[i].flow>0)
50 {
51 int di=dfs(e[i].v,min(flow,e[i].flow));
52 if(di>0)
53 {
54 e[i].flow-=di;
55 e[i^1].flow+=di;
56 return di;
57 }
58 }
59 }
60 return -1;
61 }
62
63 bool bfs()
64 {
65 if(s==t)return 0;
66 queue<int>Q;
67 while(!Q.empty())
68 Q.pop();
69 memset(dep,-1,sizeof(dep));
70 dep[s]=1;
71 Q.push(s);
72 while(!Q.empty())
73 {
74 int u=Q.front();
75 Q.pop();
76 for (int i=head[u]; i!=-1; i=e[i].nextt)
77 {
78 if ((e[i].flow>0)&&(dep[e[i].v]==-1))
79 {
80 dep[e[i].v]=dep[u]+1;
81 Q.push(e[i].v);
82 }
83 }
84 }
85 if(dep[t]!=-1)
86 return 1;
87 return 0;
88 }
89
90 int dinic()
91 {
92 int sum=0;
93 while(bfs())
94 {
95 for(int i=s; i<=t; i++)
96 cur[i]=head[i];
97 int di;
98 while((di=dfs(s,inf))!=-1)
99 sum+=di;
100 }
101 return sum;
102 }
103
104 bool Euler()
105 {
106 floww=0;
107 for (int i=1; i<=n; i++)
108 {
109 if(in[i]<out[i])
110 floww=floww+((out[i]-in[i])>>1);
111 if((in[i]+out[i])&1)
112 return 0;
113 }
114 return 1;
115 }
116
117 int main()
118 {
119 int tt;
120 scanf("%d",&tt);
121 while(tt--)
122 {
123 scanf("%d %d",&n,&m);
124 memset(in,0,sizeof(in));
125 memset(out,0,sizeof(out));
126 memset(head,-1,sizeof(head));
127 memset(cur,0,sizeof(cur));
128 s=0,t=n+1,tot=-1;
129 int x,y,z;
130 for(int i=1; i<=m; i++)
131 {
132 scanf("%d %d %d",&x,&y,&z);
133 in[y]++,out[x]++;
134 if(z==0)
135 {
136 add(x,y,1);
137 add(y,x,0);
138 }
139 }
140 if(Euler())
141 {
142 for(int i=1; i<=n; i++)
143 {
144 if(in[i]>out[i])
145 {
146 add(i,t,(in[i]-out[i])>>1);
147 add(t,i,0);
148 }
149 else if(out[i]>in[i])
150 {
151 add(s,i,(out[i]-in[i])>>1);
152 add(i,s,0);
153 }
154 }
155 if(dinic()==floww)
156 printf("possible
");
157 else
158 printf("impossible
");
159 }
160 else
161 printf("impossible
");
162 }
163 return 0;
164 }
这题我的代码再VJ上C++会超时,G++可以过。
以后最好还是用G++交,因为G+兼容C和C++,但有时候C++能过G++不能,都试一下吧如果觉得自己代码实在是没问题了。
输出double时,用G++提交时,scanf用%lf,prinf用%f,否则报错。
HDU-3472-HS BDC
题意:
给n个字符串,如果某个字符串的最后一个字母和另外一个字符串的第一个字母字母一样,那么这两个字母就可以连起来,有的字符串可以反转,问是否存在一种情况使得所有字符串都连成链。
思路:
要知道判断的是欧拉回路或者欧拉通路,二者取其一即可;
字符串的第一个字母–>字符串的最后一个字母建一条有向边,再判断字符串后面的数字x,看是否能够建立一条反向边,如果可以建立,则说明这条边是一条无向边,从而构成了一幅混合图
由于成链而不是成环,所以可以利用Dinic中的SPFA,因为SPFA无法处理环。
但是这一题首先要判断一下建的图的连通性,只有满足连通才能进行下一步的判断
AC代码:
1 #include<string.h>
2 #include<iostream>
3 #include<stdio.h>
4 #include<algorithm>
5 #include<queue>
6 #include<vector>
7 #include<map>
8 #include<cmath>
9 using namespace std;
10 #define inf 0x3f3f3f3f
11 const int N=220;
12 typedef long long ll;
13
14 int n,m,tot,s,t;
15 int head[10*N],dep[10*N],cur[10*N],floww;
16 int in[30],out[30],f[30];
17 char str[30];
18
19 struct node
20 {
21 // int u,v,flow;
22 int nextt,v,flow;
23 } e[N*N];
24
25 void add(int u,int v,int flow)
26 {
27 tot++;
28 //nextt[tot]=head[u];
29 e[tot].nextt=head[u];
30 head[u]=tot;
31 // e[tot].u=u;
32 e[tot].v=v;
33 e[tot].flow=flow;
34
35 tot++;
36 // nextt[tot]=head[v];
37 e[tot].nextt=head[v];
38 head[v]=tot;
39 //e[tot].u=v;
40 e[tot].v=u;
41 e[tot].flow=0;
42 }
43
44 int dfs(int u,int flow)
45 {
46 if(u==t)
47 return flow;
48 for(int &i=cur[u]; i!=-1; i=e[i].nextt) //注意这里的&符号,这样i增加的同时也能改变cur[u]的值,达到记录当前弧的目的
49 {
50 if((dep[e[i].v]==dep[u]+1)&&e[i].flow>0)
51 {
52 int di=dfs(e[i].v,min(flow,e[i].flow));
53 if(di>0)
54 {
55 e[i].flow-=di;
56 e[i^1].flow+=di;
57 return di;
58 }
59 }
60 }
61 return -1;
62 }
63
64 bool bfs()
65 {
66 if(s==t)
67 return 0;
68 queue<int>Q;
69 while(!Q.empty())
70 Q.pop();
71 memset(dep,-1,sizeof(dep));
72 dep[s]=1;
73 Q.push(s);
74 while(!Q.empty())
75 {
76 int u=Q.front();
77 Q.pop();
78 for (int i=head[u]; i!=-1; i=e[i].nextt)
79 {
80 if ((e[i].flow>0)&&(dep[e[i].v]==-1))
81 {
82 dep[e[i].v]=dep[u]+1;
83 Q.push(e[i].v);
84 }
85 }
86 }
87 if(dep[t]!=-1)
88 return 1;
89 return 0;
90 }
91
92 int dinic()
93 {
94 int sum=0;
95 while(bfs())
96 {
97 for(int i=s; i<=t; i++)
98 cur[i]=head[i];
99 int di;
100 while((di=dfs(s,inf))!=-1)
101 sum+=di;
102 }
103 return sum;
104 }
105
106 //bool Euler()
107 //{
108 // floww=0;
109 // for (int i=1; i<=26; i++)
110 // {
111 // if(in[i]<out[i])
112 // floww=floww+((out[i]-in[i])>>1);
113 // if((in[i]+out[i])&1)
114 // return 0;
115 // }
116 // return 1;
117 //}
118
119 int getf(int x)
120 {
121 if(f[x]==x)
122 return x;
123 return f[x]=getf(f[x]);
124 }
125
126 void merge(int x,int y)
127 {
128 int t1=getf(x);
129 int t2=getf(y);
130 f[t2]=t1;
131 }
132
133 bool judge_unpass()
134 {
135 int x=0;
136 for(int i=1; i<=26; i++)
137 {
138 if(abs(in[i]-out[i])&1)
139 x++;
140 }
141 if(x!=0&&x!=2)
142 return 1;
143 x=0;
144 for(int i=1; i<=26; i++)
145 {
146 if((in[i]+out[i])&&f[i]==i)
147 x++;
148 }
149 if(x>=2)
150 return 1;
151 return 0;
152 }
153
154 int main()
155 {
156 int cas=1,T;
157 scanf("%d",&T);
158 while(T--)
159 {
160 memset(in,0,sizeof(in));
161 memset(out,0,sizeof(out));
162 memset(head,-1,sizeof(head));
163 memset(cur,0,sizeof(cur));
164 s=0,t=27,tot=-1;
165 for(int i=1; i<=26; i++)
166 f[i]=i;
167 scanf("%d",&m);
168 for(int i=1; i<=m; i++)
169 {
170 int x;
171 scanf("%s %d",str,&x);
172 int len=strlen(str);
173 int ss=str[0]-‘a‘+1;
174 int tt=str[len-1]-‘a‘+1;
175 in[tt]++,out[ss]++;
176 merge(ss,tt);
177 if(x)
178 {
179 add(ss,tt,1);
180 //add(tt,ss,0);WA??
181 }
182 }
183 if(judge_unpass())
184 printf("Case %d: Poor boy!
",cas++);
185 else
186 {
187 int sum=0;
188 for(int i=1; i<=26; i++)
189 {
190 if(in[i]==0&&out[i]==0)
191 continue;
192 if(out[i]>in[i])
193 {
194 add(s,i,abs(in[i]-out[i])>>1);
195 sum+=abs(in[i]-out[i])>>1;
196 }
197 else if(out[i]<in[i])
198 add(i,t,abs(in[i]-out[i])>>1);
199 }
200 if(dinic()==sum)
201 printf("Case %d: Well done!
",cas++);
202 else
203 printf("Case %d: Poor boy!
",cas++);
204 }
205 }
206 return 0;
207 }
以上是关于POJ1637-Sightseeing tour/HDU-3472-HS BDC-最大流Dinic+判断混合图的欧拉图的主要内容,如果未能解决你的问题,请参考以下文章
网络流(最大流) POJ 1637 Sightseeing tour
POJ 1637 Sightseeing tour (混合图欧拉回路)
POJ1637:Sightseeing tour(混合图的欧拉回路)
POJ1637 Sightseeing tour (混合图欧拉回路)(网络流)