求混合图的欧拉回路;
在网上看了一些算法(http://baike.baidu.com/view/566040.htm),说说自己的理解,
有向图存在欧拉回路条件:每个点处度等于入度
现在可以假定每个无向边一个方向,这样假定后出度和入度差会改变2
如果所有的假设都对,那么最后每个点的出度都等于入度
但有的边可能假设错,这就需要用网络流来调整,假设最后出度大于入度为n,那么需要改变n/2条出边的方向,
选择哪儿几条那,可以通过引入一个源点到这个点容量为n/2的边,如果流的通,那么就改变这几条边的方向,同时说明其他点也是需要调整的,
所以算法就出来了
1.对每条无向边假设方向,建一条容量为1的边
2.计算每个点的出度-入度=n,大于零引入s送到点容量n/2的边,<0引入到t为n/2的边
3.计算流看是不是满流,是满流就表示可以构成欧拉回路
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<limits.h>
#include<queue>
#define MAX 220
using namespace std;
struct node
{
int y;
int c;
int f;
int next;
}a[3000];
int head[MAX];
int tot,vi[MAX],vo[MAX];
int leve[MAX];
void addedge(int x,int y ,int c)
{
a[tot].y=y;
a[tot].c=c;
a[tot].f=0;
a[tot].next=head[x];
head[x]=tot++;
a[tot].y=x;
a[tot].c=0;
a[tot].f=0;
a[tot].next=head[y];
head[y]=tot++;
}
bool bfs(int s,int t)
{
int x,y,i,u,v;
memset(leve,-1,sizeof(leve));
queue<int> q;
q.push(s);
leve[s]=0;
while(!q.empty())
{
u=q.front();
q.pop();
i=head[u];
while(i!=-1)
{
v=a[i].y;
if(a[i].c>0&&leve[v]==-1)
{
leve[v]=leve[u]+1;
q.push(v);
}
i=a[i].next;
}
}
return leve[t]!=-1;
}
int dinic(int s,int t)
{
int stack[MAX],last[MAX];
int u,v,top=1,minf,i,temp,c,edge,sum=0;
while(bfs(s,t))
{
top=1;
stack[top]=s;
for(i=s;i<=t;i++)
{
last[i]=head[i];
}
while(top)
{
u=stack[top];
if(u==t)
{
minf=INT_MAX;
for(i=1;i<top;i++)
{
edge=last[stack[i]];
if(minf>a[edge].c)
{
minf=a[edge].c;
temp=i;
}
}
for(i=1;i<top;i++)
{
edge=last[stack[i]];
a[edge].c-=minf;
a[edge].f+=minf;
a[edge^1].c+=minf;
a[edge^1].f-=minf;
}
sum+=minf;
top=temp;
continue;
}
edge=last[u];
while(edge!=-1)
{
v=a[edge].y;
c=a[edge].c;
if(c>0&&leve[u]+1==leve[v])
{
stack[++top]=v;
break;
}
edge=a[edge].next;
}
last[u]=edge;
if(edge==-1)
{
top--;
if(top!=0)
last[stack[top]]=a[last[stack[top]]].next;
}
}
}
return sum;
}
int main()
{
int t,k,i,j,sum=0,m,n;
int fu,fv;
int to,from;
bool flag;
scanf("%d",&t);
while(t--)
{
memset(vo,0,sizeof(vo));
memset(vi,0,sizeof(vi));
memset(head,-1,sizeof(head));
tot=0;
sum=0;
flag=true;
scanf("%d%d",&m,&n);
while(n--)
{
scanf("%d%d%d",&from,&to,&i);
vo[from]++;
vi[to]++;
if(!i)
{
addedge(from,to,1);
}
}
for(i=1;i<=m;i++)
{
k=vo[i]-vi[i];
if(k%2==0)
{
if(k/2>0)
{
addedge(0,i,k/2);
sum+=k/2;
}
else
{
addedge(i,m+1,-k/2);
}
}
else
{
flag=false;
break;
}
}
if(flag)
{
if(sum!=dinic(0,m+1))
flag=false;
}
if(flag)
printf("possible\n");
else
printf("impossible\n");
}
}