【HDU3488】Tour-最小费用最大流
测试地址:Tour
题目大意:在有N个点,M条有向边的有向图中找到若干个环,并使得每个点都在且只在其中一个环上,并使得环上的权值之和最小,输出这个最小值,如果不存在合法方案输出-1。
做法:这个转化方法十分神奇,我们把一个点拆成两个点,一个点连接出边,一个点连接入边,构成一个二分图,可以证明任何一个该二分图的完美匹配都对应着一个选择环的合法策略(前提是一个点拆成的两点间无边相连),那么问题就是求权值最小的完美匹配了,那么做法就很显然了,可以用KM算法做,而且更快,但是鉴于本人是想练习最小费用最大流,所以写了一个最小费用最大流的解法,920ms,不注意常数可能会爆......
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int T,n,m,first[510],tot,ans,dis[510],last[510],laste[510];
struct {int v,c,f,next;} e[200010];
bool vis[510]={0};
void insert(int a,int b,int c,int f)
{
e[++tot].v=b;
e[tot].c=c;
e[tot].f=f;
e[tot].next=first[a];
first[a]=tot;
}
bool spfa(int s)
{
int t=2*n+1;
memset(dis,-1,sizeof(dis));
queue<int> q;
q.push(s);vis[0]=1;dis[0]=0;
while(!q.empty())
{
int v=q.front();q.pop();
for(int i=first[v];i;i=e[i].next)
if (e[i].f&&(dis[e[i].v]==-1||dis[v]+e[i].c<dis[e[i].v]))
{
dis[e[i].v]=dis[v]+e[i].c;
last[e[i].v]=v;
laste[e[i].v]=i;
if (!vis[e[i].v]) {vis[e[i].v]=1;q.push(e[i].v);}
}
vis[v]=0;
}
return dis[t]!=-1;
}
int mincost()
{
int maxf=0,ans=0;
while(spfa(0))
{
ans+=dis[2*n+1];
maxf++;
int v=2*n+1;
while(v)
{
e[laste[v]].f--;
e[laste[v]^1].f++;
v=last[v];
}
}
if (maxf<n) return -1;
else return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
tot=1;
memset(first,0,sizeof(first));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
insert(0,i,0,1);insert(i,0,0,0);
insert(n+i,2*n+1,0,1);insert(2*n+1,n+i,0,0);
}
for(int i=1,a,b,c;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if (a!=b) insert(a,n+b,c,1);insert(n+b,a,-c,0);
}
printf("%d\n",mincost());
}
return 0;
}