题目链接: http://poj.org/problem?id=2135
题目大意:
给定一个图,问从1到n,再从n回到1,要求边不重复地走,最短的路是多少。
分析:
(看题解的)每条边只能用一次,所以容量是1, 费用即原图的边权,添加源点ST=0, ST向1连一条边,容量为2(1到n,再n到1,相当于从1到n两次),费用为0,(汇点可以不添加,把n直接看作汇点是可以的)
每次在残余网络中找最小费用增广路(spfa找最短路)并增广、修改残余网络,直到不存在残余网络为止。
这题一直错,第一次写费用流,注意:
1、 有负边权,采用spfa,注意加cnt[]数组判断负环;
2、 采用了循环队列,所以h++, if( h==maxn ) h= 0;
3、 这题是无向图,所以需要加双向边(容量相等,边权相等),但是每条边在残余网络里又存在一个与之对应的反向边(容量对称,边权对称,即正向边的边权是w,反边的则是-w),所以总的边数是4*M, 开始我就一直开小了, 我和lin神对于反边边权为-w 的理解是,反向边在最大流里是表示正向已经流过,之后发现了有其他路可以调整路径,所以回流的话,相应的边权应该抵消。
4、 本题的spfa的我开始由于写Edmond_karp的习惯写了 if( v==ED ) return 1; 这是错误的,spfa必须在循环结束之后才更新出所有的最短路,这点自己居然忘记了。 具体见代码了。
代码:
poj2135
1 /*2135 Accepted 1060K 16MS C++ 2710B 2012-06-19 17:19:21*/ 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <vector> 8 using namespace std; 9 10 #define mpair make_pair 11 #define pii pair<int,int> 12 #define MM(a,b) memset(a,b,sizeof(a)); 13 typedef long long lld; 14 typedef unsigned long long u64; 15 template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;} 16 template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;} 17 #define maxn 1010 18 const int inf= 2100000000; 19 20 int n,m; 21 int ST, ED; 22 int top, head[maxn]; 23 struct Edge{ 24 int u, v, c, f, next; ///c: cost, f: flow; 25 Edge(){} 26 Edge(int u, int v, int c, int f, int next): u(u),v(v),c(c),f(f),next(next){} 27 } edge[40080]; 28 void Addedge(int u,int v,int c,int f){ 29 edge[top]= Edge( u, v, c, f, head[u] ); head[u]= top++; 30 edge[top]= Edge( v, u, -c, 0, head[v] ); head[v]= top++; 31 } 32 33 bool vis[maxn]; 34 int pre[maxn]; /// record the pre-edge's index, for modifying the remain-network; 35 int que[maxn+10]; 36 int dis[maxn], cnt[maxn]; 37 bool spfa(){ 38 for(int i=ST;i<=ED;++i) dis[i]= inf, cnt[i]=vis[i]= 0, pre[i]= -1; 39 int h= 0, tail= 0; 40 que[tail++]= ST; 41 dis[ST]= 0; 42 vis[ST]= 1, cnt[ST]= 1; 43 while( h!=tail ){ /// h!=tail; because it it circle-queue; 44 int u= que[h++]; 45 if( h==maxn ) h= 0; 46 vis[u]= 0; 47 for(int i=head[u];i!=-1;i=edge[i].next){ 48 int v= edge[i].v; 49 if( edge[i].f>0 && up_min( dis[v], dis[u]+edge[i].c ) ){ 50 pre[v]= i; /// 51 if( !vis[v] ){ 52 vis[v]= 1; 53 ++cnt[v]; 54 que[tail++]= v; 55 if( tail==maxn ) tail= 0; 56 if( cnt[v]>ED ) return 0; 57 } 58 } 59 } 60 } 61 if( pre[ED] == -1 ) return 0; 62 return 1; 63 } 64 65 int solve(){ 66 int ret= 0, mf=0; 67 while( spfa() ){ 68 int t= inf; 69 for(int i=pre[ED];i!=-1;i= pre[ edge[i].u ] ) 70 up_min( t, edge[i].f ); /// t == 1 (must); 71 for(int i=pre[ED];i!=-1;i= pre[ edge[i].u ] ){ 72 edge[ i ].f -= t; 73 edge[ i^1 ].f += t; /// i^1; 74 } 75 ret+= dis[ED]; 76 } 77 return ret; 78 } 79 80 void build_graph(){ 81 top= 0; 82 fill( head, head+1+n, -1 ); 83 while(m--){ 84 int u, v, c; 85 scanf("%d%d%d", &u, &v, &c); 86 Addedge( u, v, c, 1 ); 87 Addedge( v, u, c, 1 ); 88 } 89 ST= 0, ED= n; 90 Addedge( ST, 1, 0, 2 ); 91 } 92 93 int main(){ 94 //freopen("poj2135.in","r",stdin); 95 while( cin>>n>>m ){ 96 build_graph(); 97 cout<< solve() <<endl; 98 } 99 }