POJ
来源:互联网 发布:双色球全国关注数据 编辑:程序博客网 时间:2024/06/11 00:55
就是从1走到n然后再走回来,一条边只能走一次,要求路径最短。
// MCMF 最小费用最大流#include <cstdio>#include <vector>#include <string>#include <string.h>#include <queue>#define MAX 1000 + 5#define INF 0x3fffffffusing namespace std;struct Edge { int from, to, cap, flow, cost; Edge( int u, int v, int ca, int f, int co ) : from(u),to(v),cap(ca),flow(f),cost(co){};};int n,m,s,t;vector<Edge> edges;vector<int> G[MAX];int inq[MAX];//是否在队列中int d[MAX];//距离int p[MAX];//上一条弧int a[MAX];//可改进量void init( int n ) {//初始化 for( int i = 0; i < n; i++ ) G[i].clear(); edges.clear();}void addEdge( int from, int to, int cap, int cost ) { //加边 edges.push_back( Edge( from, to, cap, 0, cost ) ); edges.push_back( Edge( to, from, 0, 0, -cost ) ); int m = edges.size(); G[from].push_back( m - 2 ); G[to].push_back( m - 1 );}bool SPFA( int s, int t, int &flow, int &cost ) { //寻找最小费用的增广路,使用引用同时修改原flow,cost fill( d, d + MAX, INF ); memset( inq, 0, sizeof( inq ) ); // 源点入队部分 d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; queue<int> q; q.push( s ); while( !q.empty () ) { int u = q.front(); q.pop(); inq[u]--; for( int i = 0; i < G[u].size(); i++ ) { Edge& e = edges[G[u][i]]; if( e.cap > e.flow && d[e.to] > d[u] + e.cost ) { //满足可增广且可变短 d[e.to] = d[u] + e.cost; p[e.to] = G[u][i]; a[e.to] = min( a[u], e.cap - e.flow ); if( !inq[e.to] ) { inq[e.to]++; q.push(e.to); } } } } if( d[t] == INF ) return false; //汇点不可达则退出 flow += a[t]; cost += d[t] * a[t]; int u = t; while( u != s ) { //更新正向边和反向边 edges[p[u]].flow += a[t]; edges[p[u] ^ 1].flow -= a[t]; u = edges[p[u]].from; } return true;}int MincotMaxflow( int s, int t, int cnt ) { int flow = 0, cost = 0; //while( SPFA( s, t, flow, cost ) ); while( cnt > 0 ) { SPFA( s, t, flow, cost ); cnt--; } return cost;}int main() { int a, b, c; while( ~scanf( "%d%d", &n, &m ) ) { init( n ); for( int i = 0; i < m; i++ ) { scanf( "%d%d%d", &a, &b, &c ); addEdge( a - 1, b - 1, 1, c ); addEdge( b - 1, a - 1, 1, c ); } printf( "%d\n", MincotMaxflow( 0, n - 1, 2 ) ); } return 0;}