poj 2135 最小费用最大流

/*
题意:有N个点的农场,之间有M条路径,问从起点走到到终点再走回起点的最短行走距离是多少,并且行走过程
中的路径不能有重复。

题解:最小费用最大流;
建图:建立无向图,边的权值均为1,保证路径只能走一次再分别加入源点和汇点,分别连接起点和终点,权值分
别为2,因为题目求的是一个来回的路径,亦即求从起点到终点的两条不重复路径即可。
从起点到终点再回起点其实是一个最大流的问题,由于还要使距离最短,因此在边加入一个值cost记录路径长度,
最小费用最大流求的是cost*权值的最小值,但是因为这个图中的所需求的权值均为1,因此直接用cost即可。最终
求最大流后将路径相加。
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

#define EMAX 500000
#define VMAX 1200

const int INF = 0xfffffff;

int head[VMAX],dis[VMAX],dist[VMAX],cur[VMAX],gap[VMAX],pre[VMAX],path[VMAX];
int EN;
struct edge
{
    int to;
    int weight;
    int cost;
    int next;
}e[EMAX];

void insert(int u,int v,int w, int c) 
{
    e[EN].to = v;
    e[EN].weight = w;
    e[EN].cost = c;
    e[EN].next = head[u];    
    head[u] = EN++;
    e[EN].to = u;
    e[EN].weight = 0;
    e[EN].cost = -c;
    e[EN].next = head[v];    
    head[v] = EN++;
}

bool spfa(int start, int t)
{
    memset(path,-1,sizeof(path));
    memset(pre,-1,sizeof(pre));
    bool vis[VMAX];
    for(int i=0; i<=t; i++)
    {
        dist[i] = INF;
        vis[i] = false;
    }
    queue<int> Q;
    dist[start] = 0;
    vis[start] = true;
    Q.push(start);
    while (!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v = e[i].to;
            if (e[i].weight && dist[u]+e[i].cost < dist[v])
            {
                pre[v] = u;
                path[v] = i;
                dist[v] = dist[u]+e[i].cost;
                if (!vis[v])
                {
                    Q.push(v);
                    vis[v] = true;
                }
            }
        }
        vis[u] = false;
    }
    if (dist[t] == INF)
        return false;
    return true;
}

int mcmf(int s, int t)//最小费用最大流
{
    queue<int> Q;
    int ret = 0;
    int maxflow = 0;
    while (spfa(0,t))//每次通过spfa求最短的允许路
    {
        ret += dist[t];
        int mw = -1;
        for(int v=t; v!=s; v=pre[v])//找出当前路径中的流量的最小容量
        {
            if (mw == -1 || mw > e[path[v]].weight)
                mw = e[path[v]].weight;
        }
        for(int v=t; v!=s; v=pre[v])//修改路径的容量,求出残余网络
        {
            e[path[v]].weight -= mw;
            e[path[v]^1].weight += mw;//更新逆向边
        }
        maxflow += mw;
    }
    return ret;
}

int main(void)
{
    int m,n,a,b,l;
    while (~scanf("%d%d",&n,&m))
    {
        memset(head,-1,sizeof(head));
        EN = 0;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&a,&b,&l);
            insert(a,b,1,l);
            insert(b,a,1,l);
        }
        insert(0,1,2,0);
        insert(n,n+1,2,0);
        printf("%d\n",mcmf(0,n+1));
    }
    return 0;
}

 

posted @ 2014-03-20 23:56  辛力啤  阅读(297)  评论(0编辑  收藏  举报