Poj2135 Farm Tour 最小费用流

题意:FJ带朋友参观自己的农场,从自己的房子出发到barn(谷仓、畜棚或车库),再从barn返回自己的房子,要求去回不走同一条路。

建图:取超级源点,并与房子连一条边,容量为2;取barn与超级汇点间的边的容量为2,中间的建图方法如代码。

/*此题建四条为有向边,是因为我从u到v建边 在从v到u建边如果存在重复走的路那么uv之间就是0流那么中间不运送东西!巧妙啊!!*/

#include <iostream>

#include <aLgorithm>

#include <cstring>

#include <queue>

#include <vector>

#include <cmath>

using namespace std;

int sumFLow;

const int MAXN = 1002;

const int MAXM = 40002;

const int INF = 1000000000;

struct Edge

{

    int u, v, cap, cost;

    int next;

}edge[MAXM<<2];

int NE;

int head[MAXN], dist[MAXN], pp[MAXN];

bool vis[MAXN];

void init()

{

    NE = 0;

    memset(head, -1, sizeof(head));

}

void addedge(int u, int v, int cap, int cost)

{

    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;

    edge[NE].next = head[u]; head[u] = NE++;

    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;

    edge[NE].next = head[v]; head[v] = NE++;

}

bool SPFA(int s, int t, int n)//n代表节点总数

{

    int i, u, v;

    queue <int> qu;

    memset(vis,false,sizeof(vis));

    memset(pp,-1,sizeof(pp));

    for(i = 0; i <= n; i++) dist[i] = INF;

    vis[s] = true; dist[s] = 0;

    qu.push(s);

    while(!qu.empty())

    {

        u = qu.front(); qu.pop(); vis[u] = false;

        for(i = head[u]; i != -1; i = edge[i].next)

        {

            v = edge[i].v;

            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)

            {

                dist[v] = dist[u] + edge[i].cost;

                pp[v] = i;

                if(!vis[v])

                {

                    qu.push(v);

                    vis[v] = true;

                }

            }

        }

    }

    if(dist[t] == INF) return false;

    return true;

}

int MCMF(int s, int t, int n) // minCostMaxFLow   n代表节点总数

{

    int fLow = 0; //总流量

    int i, minfLow, mincost;

    mincost = 0;

    while(SPFA(s, t, n))

    {

        minfLow = INF + 1;

        for(i = pp[t]; i != -1; i = pp[edge[i].u])

            if(edge[i].cap < minfLow)

                minfLow = edge[i].cap;

        fLow += minfLow;

        for(i = pp[t]; i != -1; i = pp[edge[i].u])

        {

            edge[i].cap -= minfLow;

            edge[i^1].cap += minfLow;

        }

        mincost += dist[t] * minfLow;

    }

    sumFLow = fLow; //题目需要流量,用于判断

    return mincost;

}

int main()

{

    int n, m,k;

    int u, v, c, a;

    while (scanf("%d%d", &n, &m) != EOF)

    {

        init();

        int S = 0;

        int T = n+1;

        for(int i=0;i<m;i++)

        {

                     cin>>u>>v>>c;

                     addedge(u,v,1,c);

                     addedge(v,u,1,c);

              }

              addedge(0,1,2,0);

              addedge(n,T,2,0);

        int ans = MCMF(S, T, T+1);

        printf("%d\n", ans);

    }

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值