最小费用最大流 (建图)——POJ 2135

  • 题目链接:
    http://poj.org/problem?id=2135

  • 分析:
    给出N个点和M条路,每条路有一个长度,而且从一个点到另外一个点可能不止一条路,要求从1走到N再走回去,并且同一条路只能走一次,求最短路径的长度。

  • 题解:

    1. 建图:首先,因为有重边的情况存在,所以需要用邻接链表来存储边,然后因为是无向边,所以每条边需要正着建一次,反着建一次。
      因为走过去又走回来且不能走相同的路,就相当于一个网络流:每条路的流量为1,源点到点1的流量为2,点N到汇点的流量为2,这样就能用最大流最小费用的算法求出结果了!
#define MaxN 2222
#define MaxM MaxN*40
#define INF 100000000
int N,M;
struct node
{
   int u,v,next,flow,cost;
}edge[MaxM];
int head[MaxN];
int cont;
int n;
void add(int u, int v, int flow, int cost)
{
   edge[cont].v = v;
   edge[cont].u = u;
   edge[cont].flow = flow;
   edge[cont].cost = cost;
   edge[cont].next = head[u];
   head[u] = cont++;
}

void Add(int u, int v, int flow, int cost)
{
   add(u, v, flow, cost);  //正向边
   add(v, u, 0, -cost);      //反向退流边
}
//建图:
int a,b,c;
for(int i=0;i<M;i++)
{
    scanf("%d%d%d", &a, &b, &c);
    Add(a,b,1,c);
    Add(b,a,1,c);
}
Add(0,1,2,0);   
Add(N,N+1,2,0);
  • AC代码:
/*************************************************************************
    > File Name: FarmTourHDU2135.cpp
    > Author: Akira 
    > Mail: qaq.febr2.qaq@gmail.com 
    > Created Time: 2016年08月12日 星期五 11时01分29秒
 ************************************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <set>
#include <list>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))

using namespace std;

#define MaxN 2222
#define MaxM MaxN*40
#define INF 100000000

int N,M;

struct node
{
    int u,v,next,flow,cost;
}edge[MaxM];
int head[MaxN];
int cont;
int n;
void add(int u, int v, int flow, int cost)
{
    edge[cont].v = v;
    edge[cont].u = u;
    edge[cont].flow = flow;
    edge[cont].cost = cost;
    edge[cont].next = head[u];
    head[u] = cont++;
}

void Add(int u, int v, int flow, int cost)
{
    add(u, v, flow, cost);
    add(v, u, 0, -cost);
}

void init()
{
    MST(head,-1);
    cont = 0;
    n = 0;
}

bool vis [MaxN];
int dist [MaxN];
int pre [MaxN];
int aug;
int ans;
bool SPFA(int s, int t)
{
    int k, p, V;
    queue<int> q;
    MST(pre, -1);
    CLR(vis);
    for(int i=0;i<=n;i++)
        dist[i] = INF;
    q.push(s);
    vis[s] = 1;
    dist[s] = 0;
    while(!q.empty())
    {
        k = q.front();
        q.pop();
        vis[k] = 0;
        for(p = head[k]; p!=-1; p = edge[p].next)
        {
            V = edge[p].v;
            if(edge[p].flow && (edge[p].cost + dist[k] < dist[V]))
            {
                dist[V] = edge[p].cost + dist[k];
                pre[V] = p;
                if(!vis[V])
                {
                    q.push(V);
                    vis[V] = 1;
                }
            }
        }
    }
    if(dist[t] == INF) return false;
    aug = INF+1;
    for(p = pre[t]; p != -1; p = pre[edge[p].u])
    {
        aug = min(aug, edge[p].flow);
    }

    for(p = pre[t]; p != -1; p = pre[edge[p].u])
    {
        edge[p].flow -= aug;
        edge[p^1].flow += aug;
    }
   // cout << ans << endl;
    ans += dist[t]*aug;
    return true;
}

int main()
{
    while(~scanf("%d%d", &N, &M))
    {
        init();
        int a,b,c;
        for(int i=0;i<M;i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            Add(a,b,1,c);
            Add(b,a,1,c);
        }
        Add(0,1,2,0);
        Add(N,N+1,2,0);
        int Ans = 0;
        n = N+1;
        ans = 0;
        while(SPFA(0,N+1));
        Ans += ans;
        cout << Ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值