费用流
混合欧拉回路
#include<cstdio> #include<cstring> #include<queue> #define N 300 #define inf 100000000 using namespace std; typedef long long ll; int n,cnt; int head[N],pre[N],vis[N],in[N],out[N]; int dis[N]; int ans,sum,suma,sumb; struct Edge{ int u,v,c,next; ll w; }edge[8010]; void init(){ memset(head,-1,sizeof(head)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); cnt=sum=ans=suma=sumb=0; } void addedge(int u,int v,int cap,int cost){ edge[cnt].u=u; edge[cnt].v=v; edge[cnt].c=cap; edge[cnt].w=cost; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].u=v; edge[cnt].v=u; edge[cnt].c=0; edge[cnt].w=-cost; edge[cnt].next=head[v]; head[v]=cnt++; } bool spfa(){ int i,j; queue<int>q; q.push(0); for(i=1;i<=n;i++){ dis[i]=inf; vis[i]=0; } dis[0]=0,vis[0]=1; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].c && dis[v] > dis[u]+edge[i].w){ dis[v]=dis[u]+edge[i].w; pre[v]=i; if(!vis[v]){ vis[v]=1; q.push(v); } } } } if(dis[n]==inf)return 0; return 1; } void end(){ int u,p,cap=-1; for(u=n;u;u=edge[p].u){ p=pre[u]; if(cap==-1 || cap>edge[p].c) cap=edge[p].c; } suma+=cap; for(u=n;u;u=edge[p].u){ p=pre[u]; edge[p].c-=cap; edge[p^1].c+=cap; ans+=cap*edge[p].w; } } int main(){ int t,T,i; int v,e,s,tt; int vv,u,a,b; scanf("%d",&T); for(t=1;t<=T;t++){ scanf("%d %d %d %d",&v,&e,&s,&tt); init(); for(i=1;i<=e;i++){ scanf("%d %d %d %d",&u,&vv,&a,&b); if(a<=b){ addedge(u,vv,1,b-a); //建这条边,如果费用流经过这条边,那么u的out++,in-- 并且vv的in++,out-- in[vv]++,out[u]++; sum+=a; } else{ addedge(vv,u,1,a-b); //建这条边,如果费用流经过这条边,那么vv的out++,u的in++ sum+=b; } } n=v+1; in[s]++,out[tt]++; for(i=1;i<=v;i++) if(in[i]<out[i]){ addedge(0,i,out[i]-in[i],0); sumb+=out[i]-in[i]; } else if(in[i]>out[i]) addedge(i,n,in[i]-out[i],0); while(spfa()) end(); if(suma==sumb) printf("Case %d: %d\n",t,ans+sum); else printf("Case %d: impossible\n",t); } return 0; }