【题目大意】给定一个混合图(有无向边也有有向边),问图中是否存在欧拉回路。另外该题保证存在一个顶点,使得其他顶点都能到达。即保证的连通性,我们只需要考虑度的限制就可以了。
【算法分析】对于有向边,度是不可改变的。只有无向边可以变换方向。
我们先把无向边任意地定一个方向。
1、如果有边的总度数为奇数,那么肯定不存在欧拉回路。
2、对于出度大于入度的点连边[S,i],c=-du[i]/2。du为入度-出度。
对于入度大于出度的点连边[i,T],c=du[i]/2。
然后把无向边都按你定的方向加入图中,容量都为1。
进行最大流。
如果最后与源或汇相连的边都是满流,则符合条件。
————————————————————————————————————————————
为什么要这样呢?
我们可以想象,最大流流过那条边,相当于把这条边反向,而如果要让du[i]变为0,那么必须反向du[i]/2条边。所以源汇相连的边容量为du[i]/2。然后中间的可以看成一个二分图,模拟一下就会知道是什么意思。
【其它】 6389700 edward2 1637 Accepted 420K 0MS G++ 2796B 2010-01-30 18:36:51 排得挺靠前啊。。。虽然都是0MS,ORZ
【CODE】
#include
#define Ed 20001
struct gtp{int x,y,c,op,next;}g[Ed];
struct gtp2{int x,y,next;}G[Ed];
int n,e,m,E;
int du[N],wxn[N],ls[N],LS[N];
int fa[N],cur[N],num[N],d[N];
void addEdge(int x,int y){
E++;
G[E].x=x; G[E].y=y; G[E].next=LS[x]; LS[x]=E;
}
void init(){
E=0;
memset(du,0,sizeof(du));
memset(wxn,0,sizeof(wxn));
memset(LS,0,sizeof(LS));
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
int x,y,q;
scanf("%d%d%d",&x,&y,&q);
if (q==1){
du[x]–;
du[y]++;
}
else{
addEdge(x,y);
du[x]–;
du[y]++;
}
}
}
void addedge(int x,int y,int c){
e++;
g[e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=e; g[e].c=c; g[e].op=e+1;
e++;
g[e].x=y; g[e].y=x; g[e].next=ls[y]; ls[y]=e; g[e].c=0; g[e].op=e-1;
}
void build(){
e=0;
memset(ls,0,sizeof(ls));
for (int i=1;i<=n;i++){
if (du[i]<0) addedge(0,i,-du[i]/2);
if (du[i]>0) addedge(i,n+1,du[i]/2);
for (int t=LS[i];t!=0;t=G[t].next)
addedge(G[t].x,G[t].y,1);
}
}
void relabel(int k){
int mm=n+1;
cur[k]=ls[k];
for (int t=ls[k];t!=0;t=g[t].next)
if (g[t].c>0 && d[g[t].y]
}
void change(){
int nf=0x7FFFFFFF;
for (int i=n+1;i!=0;i=g[fa[i]].x)
if (g[fa[i]].c
g[fa[i]].c-=nf;
g[g[fa[i]].op].c+=nf;
}
}
void sap(){
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
for (int i=0;i<=n+1;i++) cur[i]=ls[i];
int i=0;
while (d[0]
if (g[cur[i]].c>0 && d[g[cur[i]].y]+1==d[i]) break;
if (cur[i]==0){
if (–num[d[i]]==0) break;
relabel(i);
num[d[i]]++;
if (i!=0) i=g[fa[i]].x;
}
else{
fa[g[cur[i]].y]=cur[i];
i=g[cur[i]].y;
if (i==n+1){
change();
i=0;
}
}
}
}
bool flag(){
for (int i=1;i<=n;i++)
if (du[i]%2!=0) return false;
for (int i=1;i<=n;i++)
for (int t=ls[i];t!=0;t=g[t].next)
if ((t&1) && (g[t].x==0 || g[t].y==n+1) && g[t].c!=0) return false;
return true;
}
int main(){
int tc;
scanf("%d",&tc);
for (int i=0;i
build();
sap();
if (flag()) printf("possiblen");
else printf("impossiblen");
}
return 0;
}
Orz!!!!!
回复fatboy_cw:回ORZ。。。向退役的GDOIER致敬。。。
回复edward_mj:话说我不是GD的……….-_-|||
回复fatboy_cw:。。。认错牛了,这下蛋疼