这道题是一个混合图欧拉回路问题。
建图方法:将无向图随意定向,计算每个点的入度和出度,令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; }