poj 2135 Farm Tour 最小费用最大流建图跑最短路

题目链接

题意:无向图有N(N <= 1000)个节点,M(M <= 10000)条边;从节点1走到节点N再从N走回来,图中不能走同一条边,且图中可能出现重边,问最短距离之和为多少?

思路:很经典的构图(看题解的);每条原图中的边赋予cap为1,表示只走一次。超级源点s和汇点t分别和起点终点连边,cap为2,这里cap为2就直接限制了只能有两次最大流;同时最大流中以权值限制得到的就是最小费用;很注意的一点就是此题为无向图带权值,建图时每条有向边建成两条即总边数为4*M。由于spfa找最短路是有方向的,所以这样并不会出现一条边找两次的可能;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<stack>
#include<set>
#include<map>
#include<queue>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define MSi(a) memset(a,0x3f,sizeof(a))
#define inf 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1|1
typedef long long ll;
#define A first
#define B second
#define MK make_pair
typedef __int64 ll;
template<typename T>
void read1(T &m)
{
    T x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    m = x*f;
}
template<typename T>
void read2(T &a,T &b){read1(a);read1(b);}
template<typename T>
void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
template<typename T>
void out(T a)
{
    if(a>9) out(a/10);
    putchar(a%10+'0');
}
int T,kase = 1,i,j,k,n,m,s,t;
const int M = 10007;
int head[M],tot;
struct Edge{
    int from,to,cap,flow,Next,w;
    Edge(){}
    Edge(int f,int to,int cap,int Next,int w):from(f),to(to),cap(cap),Next(Next),w(w),flow(0){}
}e[M<<2];
inline void ins(int u,int v,int w,int cap)
{
    e[++tot] = Edge{u,v,cap,head[u],w};
    head[u] = tot;
}
int d[2007],pre[2007],inq[2007],a[2007];
bool spfa()
{
    MSi(d);MS0(inq);
    d[s] = 0;
    queue<int> q;
    q.push(s);
    inq[s] = 1;pre[s] = 0;a[s] = inf;
    while(!q.empty()){
        int u = q.front();q.pop();
        inq[u] = 0;
        for(int id = head[u];id; id = e[id].Next){
            int v = e[id].to;
            if(d[v] > d[u] + e[id].w && e[id].cap > e[id].flow){
                d[v] = d[u] + e[id].w;
                pre[v] = id;
                a[v] = min(a[u],e[id].cap - e[id].flow);
                if(!inq[v]){ q.push(v); inq[v] = 1;}
            }
        }
    }
    return d[t] != inf;
}
void solve()
{
    ll ans = 0;
    while(spfa()){
        ans += d[t]*a[t];
        for(int u = t;u != s;u = e[pre[u]].from){
            e[pre[u]].flow += a[t];
            e[pre[u]^1].flow -= a[t];
        }
    }
    printf("%I64d\n",ans);
}
int main()
{
    while(scanf("%d%d",&n,&m) == 2){
        MS0(head);tot = 1;
        s = 0,t = n+1;
        int u,v,w;
        rep0(i,0,m){
            read3(u,v,w);
            ins(u,v,w,1);ins(v,u,-w,0);// ** 下面不能省略,因为是无向输入的.
            ins(v,u,w,1);ins(u,v,-w,0); 
        }
        ins(s,1,0,2);ins(1,s,0,0);
        ins(n,t,0,2);ins(t,n,0,0);
        solve();
    }
    return 0;
}

 

posted @ 2016-04-04 22:44  hxer  阅读(285)  评论(0编辑  收藏  举报