POJ 2135 Farm Tour 最小费用流

费用流算法详解
本文介绍了一个具体的费用流问题,即如何从起点到达终点并返回,过程中需经过每一个点且不重复行走路线。通过构建特定图模型,利用SPFA算法进行最短路径计算,并通过反复更新最小费用流来找到最优解。

有N的点,1是farmer john的家  n是barn要求从1开始走到n再走回来,不许走重复的路线,使之能从1走到n在走回来,且要经过每个点。费用流的模型。

建立一个新源点容量为2,费用为0连向点1,然后n连向一个汇点,原来的图是无向图,所以要加2个有向边求解。之后就是费用流了

题目保证可以走回来的,这样加边的原因是有向边是在网络中有一定的关系的,有流量从A到B的流过,那么在最终的网络流中一定不可能从B到A流回来

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

 

class mincost
{
private:
    const static int V = 1001;
    const static int E = 1000001;
    const static int INF = 0x7ffffff;

    struct Edge
    {
        int v, cap, cost;
        Edge *next;
    } pool[E], *g[V], *pp, *pree[V];
    int T, S, dis[V], pre[V];
    int n, m;
    void SPFA();
    inline void addedge(int i, int j, int cap, int cost);
public:
    bool initialize();
    void mincost_maxflow();
};

void mincost::mincost_maxflow()
{
    int flow = 0;
    while (true)
    {
        SPFA();
        if (dis[T] == INF)
            break;
        int minn = INF;
        for (int i = T; i != S; i = pre[i])
            minn = min(minn, pree[i]->cap);
        for (int i = T; i != S; i = pre[i])
        {
            pree[i]->cap -= minn;
            pool[(pree[i] - pool)^0x1].cap += minn;
            flow += minn * pree[i]->cost;
        }
    }
    printf("%d\n", flow);
}

void mincost::SPFA()
{
    bool vst[V] = {false};
    int cirq[V];
    int tail = 0, u;
    fill(dis, dis + T + 1, 0x7ffffff);
    cirq[0] = S;
    vst[S] = 1;
    dis[S] = 0;
    for (int j = 0; j <= tail; j++)
    {
        int v = cirq[j % n];
        for (Edge *i = g[v]; i != NULL; i = i->next)
        {
            if (!i->cap)
                continue;
            u = i->v;
            if (i->cost + dis[v] < dis[u])
            {
                dis[u] = i->cost + dis[v];
                pree[u] = i;
                pre[u] = v;
                if (!vst[u])
                {
                    tail++;
                    cirq[tail % n] = u;
                    vst[u] = true;
                }
            }
        }
        vst[v] = false;
    }
}

void mincost::addedge(int i, int j, int cap, int cost)
{
    pp->cap = cap;
    pp->v = j;
    pp->cost = cost;
    pp->next = g[i];
    g[i] = pp++;
}

bool mincost::initialize()
{
    if (scanf("%d %d", &n, &m) != 2)
        return false;
    memset(g, 0, sizeof (g));
    pp = pool;
    S = 0, T = n + 1;
    int v, u, c;
    addedge(S, 1, 2, 0);
    addedge(1, S, 0, 0);
    addedge(n, T, 2, 0);
    addedge(T, n, 0, 0);
    n += 2;
    for (int i = 0; i < m; i++)
    {
        scanf("%d %d %d", &v, &u, &c);
        addedge(v, u, 1, c);
        addedge(u, v, 0, -c);
        addedge(u, v, 1, c);
        addedge(v, u, 0, -c);
    }
    return true;
}
mincost g;

int main()
{
    while (g.initialize())
        g.mincost_maxflow();
    return 0;
}

转载于:https://www.cnblogs.com/ronaflx/archive/2010/09/19/1831291.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值