POJ 3488 最小费用最大流(环)
这是个有环的最小费用最大流(简直就是A计划的简化版)
主要说下从cxlove那学来的构图方法,对于环,环上的每个节点的出度和入度都是相等的,由于每个点只经过一次,
所以我们可以将点二分(1——N,N+1——2*N),然后创造一个原点和汇点,原点到每个点(1——N)的容量为1(表示入度为1)
每个点(N+1————2N)到汇点的容量为1(表示出度为1),这就是对于环的处理了。
剩下的构图根据点之间的关系。
代码
#include<stdio.h> #include<string.h> #include<queue> #define INF 1<<29 #define val 516 using namespace std; struct edge { int u,v,f,w,c,next; }e[60005]; int tot,n,m,s,t,head[val],dist[val],pre[val]; bool inq[val]; void create_link();//构图 int mincost_maxflow();//最小费用最大流 int main() { int ans,cas; for(scanf("%d",&cas);cas;cas--) { scanf("%d %d",&n,&m); create_link(); ans=mincost_maxflow(); printf("%d\n",ans); } return 0; } void create_link() { void add_edge(int u,int v,int f,int c); tot=0; int i,a,b,c; s=0,t=2*n+1; memset(head,-1,sizeof(head)); for(i=0;i<m;i++) { scanf("%d %d %d",&a,&b,&c); add_edge(a,b+n,INF,c); add_edge(b+n,a,0,-c); } for(i=1;i<=n;i++)//限制入度 { add_edge(s,i,1,0); add_edge(i,s,0,0); } for(i=1;i<=n;i++)//限制出度 { add_edge(i+n,t,1,0); add_edge(t,i+n,0,0); } } void add_edge(int u,int v,int f,int c) { e[tot].u=u,e[tot].v=v,e[tot].f=f; e[tot].c=c,e[tot].next=head[u],head[u]=tot++; } int mincost_maxflow() { bool spfa(); int flow ,sum=0,i; while(1) { if(spfa()==false) break; flow=INF; for(i=pre[t];i!=-1;i=pre[e[i].u]) if(e[i].f<flow) flow=e[i].f; sum+=flow*dist[t]; for(i=pre[t];i!=-1;i=pre[e[i].u]) { e[i].f-=flow; e[i^1].f+=flow; } } return sum; } bool spfa() { int i,w,x; queue<int>q; memset(inq,false,sizeof(inq)); memset(pre,-1,sizeof(pre)); for(i=s;i<=t;i++) dist[i]=INF; dist[s]=0; q.push(s); while(!q.empty()) { x=q.front(); q.pop(); for(i=head[x];i!=-1;i=e[i].next) { w=e[i].v; if(e[i].f&&dist[w]>dist[x]+e[i].c) { dist[w]=dist[x]+e[i].c; pre[w]=i; if(!inq[w]) { q.push(w); inq[w]=true; } } } inq[x]=false; } if(dist[t]==INF) return false; else return true; }