传送门
建模非常神奇的脑子题(不适合我)
一句话题意:混合图欧拉回路
首先我们知道如果一个图存在欧拉图的话那么每个点的入度要等于出度
那么对于单向边我们可以确定下来入度出度可以直接加到点上然后删掉
双向边我们需要给它定向来决定是否存在欧拉回路
我们需要让每个点达到流量平衡也就是入度=出度
我们先任意定向使每个点现在有一个确定的入度和出度
然后我们需要重定向是流量平衡
所以我们将入度>出度的点连源点 入度<出度的连汇点 等于的不需要考虑因为本来已经符合要求了嘛
流量是delta/2(delta是入度出度差的绝对值) 这个除以2是因为一条边变向的话其实是更改了出度也更改了入度 所以变化值是两倍 流量就要设为原来的1/2
其他的边按照我们刚才任意定向的连接流量为1的边即可(最后残存流量为1的话就是保持原样 0的话就是反向)
这样的话我们只需要看是否是满流就可以了
注意初始化。。。
附代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 20021225
#define ll long long
using namespace std;
struct edge{int to,lt,f;}e[3010];
queue<int> que;int in[410],cnt=-1,s,t,dep[410];
int ii[410],oo[410],xx[1010],yy[1010],d[1010];
void add(int x,int y,int f)
{
e[++cnt].f=f;e[cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;
e[++cnt].f=0;e[cnt].to=x;e[cnt].lt=in[y];in[y]=cnt;
}
bool bfs()
{
while(!que.empty()) que.pop();
memset(dep,0,sizeof(dep));
dep[s]=1;que.push(s);
while(!que.empty())
{
int x=que.front();que.pop();
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to;
if(!dep[y]&&e[i].f)
{
dep[y]=dep[x]+1;
if(y==t) return 1;
que.push(y);
}
//printf("QAQ");
}
}
return 0;
}
int dfs(int x,int flow)
{
if(x==t||!flow) return flow;
int cur=0;
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to;
if(dep[y]==dep[x]+1&&e[i].f)
{
int tmp=dfs(y,min(e[i].f,flow-cur));
cur+=tmp;e[i].f-=tmp;e[i^1].f+=tmp;
if(cur==flow) break;
}
}
dep[x]=-1;
return cur;
}
int dinic()
{
int ans=0;
while(bfs()) ans+=dfs(s,inf);
return ans;
}
int main()
{
int tt,n,m,tot,i;
scanf("%d",&tt);
while(tt--)
{
//printf("%d
",y)
scanf("%d%d",&n,&m);
memset(in,0,sizeof(in));
memset(ii,0,sizeof(ii));
memset(oo,0,sizeof(oo));
cnt=1;tot=0;s=n+1;t=s+1;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&xx[i],&yy[i],&d[i]);
oo[xx[i]]++;ii[yy[i]]++;
if(!d[i]) add(xx[i],yy[i],1);
}
for(i=1;i<=n;i++)
{
if((oo[i]-ii[i])&1) break;
if(oo[i]-ii[i]>0)
add(s,i,(oo[i]-ii[i])/2),tot+=(oo[i]-ii[i])/2;
else if(oo[i]-ii[i]<0)
add(i,t,(ii[i]-oo[i])/2);
}
if(i<=n) printf("impossible
");
else
{
if(dinic()==tot) printf("possible
");
else printf("impossible
");
}
}
return 0;
}