原题:http://acm.hdu.edu.cn/showproblem.php?pid=3488
题意:
有n个点,m条有向带权边;
求一些环,使得每个点属于且仅属于一个环;
问环边的权值和的最小值;
思路:
拆点,建图,跑一个费用流;
源点到节点,流量为1,花费为0(s, i, 0, 1);
节点到节点,流量为1, 花费为边权值(u, v+n, cos, 1);
节点到汇点,流量为1,花费为0(i+n, t, 0, 1);
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#define oo 0x3f3f3f3f
#define maxn 410
using namespace std;
struct Edge
{
int u, v, c, f;
Edge( int u, int v, int c, int f ):u(u),v(v),c(c),f(f){}
};
struct Mcmf
{
int n, src, dst;
vector<Edge> edge;
vector<int> g[maxn];
int dis[maxn], ext[maxn], pth[maxn];
void init( int nn, int s, int d )
{
n = nn;
src = s;
dst = d;
for( int i=1; i<=n; i++ )
g[i].clear();
edge.clear();
}
void add_edge( int u, int v, int c, int f )
{
g[u].push_back( edge.size() );
edge.push_back( Edge(u,v,c,f) );
g[v].push_back( edge.size() );
edge.push_back( Edge(v,u,-c,0) );
}
bool spfa( int &flow, int &cost )
{
queue<int> qu;
memset( dis, 0x3f, sizeof(dis) );
qu.push( src );
dis[src] = 0;
ext[src] = true;
pth[src] = -1;
while( !qu.empty() )
{
int u = qu.front();
qu.pop();
ext[u] = false;
for( int t=0; t<g[u].size(); t++)
{
Edge &e = edge[g[u][t]];
if( e.f && dis[e.v]>dis[e.u]+e.c )
{
dis[e.v] = dis[e.u]+e.c;
pth[e.v] = g[u][t];
if( !ext[e.v] )
{
ext[e.v] = true;
qu.push( e.v );
}
}
}
}
if( dis[dst]==oo ) return false;
int flw = oo;
for( int eid=pth[dst]; eid!=-1; eid=pth[edge[eid].u] )
flw = min( flw, edge[eid].f );
for( int eid=pth[dst]; eid!=-1; eid=pth[edge[eid].u] )
{
edge[eid].f -= flw;
edge[eid^1].f += flw;
}
flow += flw;
cost += flw*dis[dst];
return true;
}
void mcmf( int &flow, int &cost )
{
flow = cost = 0;
while( spfa(flow,cost) );
}
};
int n, m;
Mcmf M;
int main()
{
int cas;
scanf( "%d", &cas);
while(cas--)
{
scanf( "%d%d", &n, &m);
int s = 0, t = n*2+1;
M.init(t+1, s, t);
for(int i = 1;i<=m;i++)
{
int u, v, cos;
scanf("%d%d%d", &u, &v, &cos);
M.add_edge(u, v+n, cos, 1);
}
for(int i = 1;i<=n;i++)
{
M.add_edge(M.src, i, 0, 1);
M.add_edge(i+n, M.dst, 0, 1);
}
int flow, cost;
M.mcmf(flow, cost);
printf("%d\n", cost);
}
return 0;
}