这道题是一个混合图欧拉回路问题。
建图方法:将无向图随意定向,计算每个点的入度和出度,令calc[i] = abs(in[i] - out[i])/2。如果calc[i]为奇数,那么肯定不存在欧拉回路;如果所有点calc[i]都为偶数,那么先将有向边删去,然后按照一开始的定向方法构图,并且对于每个入度小于出度的点则添加一条源点到该点的边,容量为calc[i];反之则连一条该点到汇点的边,容量为calc[i],最后再做一次最大流,如果为满流,则存在欧拉回路,否则不存在。
ps:这道题会有重边,所以用邻接矩阵不太好,最好写成邻接表的形式。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 500;
const int maxm = 5000;
struct Node
{
int c,pos,next;
}E[maxm];
struct Edge
{
int x,y,op;
}edge[maxm];
int T,n,m;
int head[maxn];
int id1[maxn],id2[maxn],tmp[maxn];
int cur[maxn],dis[maxn],gap[maxn],pre[maxn];
int s,t,NE,NV;
void init()
{
freopen("poj1637.in","r",stdin);
freopen("poj1637.out","w",stdout);
}
inline void checkmin(int &a,int b)
{
if(a == -1 || a > b)a = b;
}
int abs(int x)
{
if(x >= 0)return x;
else return -x;
}
int sap()
{
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
for(int i = 0;i < NV;i++)cur[i] = head[i];
int u = pre[s] = s,maxflow = 0,aug = -1;
gap[0] = NV;
while(dis[s] < NV)
{
loop: for(int &i = cur[u];i != -1;i = E[i].next)
{
int v = E[i].pos;
if(E[i].c && dis[u] == dis[v] + 1)
{
checkmin(aug,E[i].c);
pre[v] = u;
u = v;
if(v == t)
{
maxflow += aug;
for(u = pre[u];v != s;v = u,u = pre[u])
{
E[cur[u]].c -= aug;
E[cur[u]^1].c += aug;
}
aug = -1;
}
goto loop;
}
}
int mind = NV;
for(int i = head[u];i != -1;i = E[i].next)
{
int v = E[i].pos;
if(E[i].c && (mind > dis[v]))
{
cur[u] = i;
mind = dis[v];
}
}
if((--gap[dis[u]]) == 0)break;
gap[dis[u] = mind + 1]++;
u = pre[u];
}
return maxflow;
}
void Insert(int u,int v,int c)
{
E[NE].c = c; E[NE].pos = v;
E[NE].next = head[u];head[u] = NE++;
E[NE].c = 0; E[NE].pos = u;
E[NE].next = head[v];head[v] = NE++;
}
void solve()
{
memset(E,0,sizeof(E));
memset(head,-1,sizeof(head));
s = 0;t = n + 1;NE = 0;NV = n + 2;
for(int i = 1;i <= n;i++)
{
tmp[i] = abs(id1[i] - id2[i]);
if(tmp[i] & 1)
{
printf("impossible\n");
return;
}
tmp[i] >>= 1;
}
for(int i = 1;i <= m;i++)
{
if(edge[i].op == 0)
{
Insert(edge[i].x,edge[i].y,1);
}
}
int comp = 0;
for(int i = 1;i <= n;i++)
{
if(id1[i] > id2[i])Insert(s,i,tmp[i]),comp += tmp[i];
else if(id1[i] < id2[i])Insert(i,t,tmp[i]);
}
if(comp == sap())printf("possible\n");
else printf("impossible\n");
}
void readdata()
{
scanf("%d",&T);
for(int i = 1;i <= T;i++)
{
memset(edge,0,sizeof(edge));
memset(id1,0,sizeof(id1));
memset(id2,0,sizeof(id2));
memset(tmp,0,sizeof(tmp));
scanf("%d%d",&n,&m);
for(int j = 1;j <= m;j++)
{
scanf("%d%d%d",&edge[j].x,&edge[j].y,&edge[j].op);
id1[edge[j].x]++,id2[edge[j].y]++;
}
solve();
}
}
int main()
{
init();
readdata();
return 0;
}