题意:在一个王国有N个城市,M条路。选择N条路,构成一个环路。求出最小距离。
解析:构图,最小费用最大流。将源点和终点至个点花费记作0,然后将所有路径流量记作1或同一值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 10000;
const int maxm = 100000;
const int INF = 0xfffffff;
struct Edge{
int to, next, cap, flow, cost;
}edge[ maxm ];
int head[ maxn ], tol;
int pre[ maxn ], dis[ maxn ];
bool vis[ maxn ];
int N;
void init( int n ){
N = n;
tol = 0;
memset( head, -1, sizeof( head ) );
}
void addedge( int u, int v, int cap, int cost ){
edge[ tol ].to = v;
edge[ tol ].cap = cap;
edge[ tol ].cost = cost;
edge[ tol ].flow = 0;
edge[ tol ].next = head[ u ];
head[ u ] = tol++;
edge[ tol ].to = u;
edge[ tol ].cap = 0;
edge[ tol ].cost = -cost;
edge[ tol ].flow = 0;
edge[ tol ].next = head[ v ];
head[ v ] = tol++;
}
bool spfa( int s, int t ){
queue< int > q;
for( int i = 0; i < N; ++i ){
dis[ i ] = INF;
vis[ i ] = false;
pre[ i ] = -1;
}
dis[ s ] = 0;
vis[ s ] = true;
q.push( s );
while( !q.empty( ) ){
int u = q.front();
q.pop();
vis[ u ] = false;
for( int i = head[ u ]; i != - 1; i = edge[ i ].next ){
int v = edge[ i ].to;
if( edge[ i ].cap > edge[ i ].flow && dis[ v ] > dis[ u ] + edge[ i ].cost ){
dis[ v ] = dis[ u ] + edge[ i ].cost;
pre[ v ] = i;
if( !vis[ v ] ){
vis[ v ] = true;
q.push( v );
}
}
}
}
if( pre[ t ] == -1 )
return false;
else
return true;
}
int minCostMaxflow( int s, int t, int &cost ){
int flow = 0;
cost = 0;
while( spfa( s, t ) ){
int Min = INF;
for( int i = pre[ t ]; i != - 1; i = pre[ edge[ i ^ 1 ].to ] ){
if( Min > edge[ i ].cap - edge[ i ].flow )
Min = edge[ i ].cap - edge[ i ].flow;
}
for( int i = pre[ t ]; i != -1; i = pre[ edge[ i ^ 1 ].to ] ){
edge[ i ].flow += Min;
edge[ i ^ 1 ].flow -= Min;
cost += edge[ i ].cost * Min;
}
flow += Min;
}
return cost;
}
int main(){
int Case;
int n, m;
scanf( "%d", &Case );
while( Case-- ){
scanf( "%d%d", &n, &m );
int N = 2 * n + 2;
int start = 0, end = 2 * n + 1;
init( N );
for( int i = 1; i <= n; ++ i ){
addedge( 0, i, 1, 0 );
}
for( int i = 1; i <= n; ++i ){
addedge( n + i, end, 1, 0 );
}
int x, y, value;
for( int i = 0; i < m; ++i ){
scanf( "%d%d%d", &x, &y, &value );
addedge( x, n + y, 1, value );
}
int cost;
int ans = minCostMaxflow( start, end, cost );
cout << ans << endl;
}
return 0;
}