zoukankan      html  css  js  c++  java
  • POJ 2135 最小费用流入门题

    题目链接: 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 }
    一毛原创作品,转载请注明出处。
  • 相关阅读:
    interview
    lvs简介
    编译参数说明
    nginx-arch
    network
    linux 密码修改方法
    ps命令详解
    sed 命令+正则表达式
    LINUX SCP 命令详解
    linux下mysql的root密码忘记解决方
  • 原文地址:https://www.cnblogs.com/yimao/p/2555080.html
Copyright © 2011-2022 走看看