POJ 2135 Farm Tour(最小费用最大流)解题报告

2016-12-12 576 次浏览 解题报告

解题思路

使用费用流求解。首先把题中所有的边都按流量为 1,费用为路径长度加边,这样就保证了每条路只能走一次,且求出来的最小费用就是最短路径长度。之后再把源点到 1 以及 n 到汇点都加一条流量为 2,费用为 0 的边,这是为了支持题目中的往返操作。这样跑一边最小费用最大流即可求出答案。

参考代码

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

const int INF = 0x3f3f3f3f;
const int MAXN = 1002;
const int MAXM = 20002;

struct edge {
    int u, v, f, c;
    int next;
} e[MAXM<<1];

int cnt, head[MAXN];
bool vis[MAXN];
int dis[MAXN], pre[MAXN];

void Init() {
    cnt = 0;
    memset(head, -1, sizeof head);
}

void AddEdge(int u, int v, int f, int c) {
    e[cnt].u = u;
    e[cnt].v = v;
    e[cnt].f = f;
    e[cnt].c = c;
    e[cnt].next = head[u];
    head[u] = cnt++;
    e[cnt].u = v;
    e[cnt].v = u;
    e[cnt].f = 0;
    e[cnt].c = -c;
    e[cnt].next = head[v];
    head[v] = cnt++;
}

bool SPFA(int s, int t) {
    queue<int>q;
    q.push(s);
    memset(dis, 0x3f, sizeof dis);
    memset(pre, -1, sizeof pre);
    memset(vis, false, sizeof vis);
    dis[s] = 0;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i=head[u]; ~i; i=e[i].next) {
            int v = e[i].v;
            int f = e[i].f;
            int c = e[i].c;
            if(f>0 && dis[u]+c<dis[v]) {
                dis[v] = dis[u] + c;
                pre[v] = i;
                if(!vis[v]) {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1) return false;
    else return true;
}

pair<int, int> MinCostMaxFlow(int s, int t) {
    int max_flow = 0, min_cost = 0;
    while(SPFA(s, t)) {
        int flow = INF;
        for(int i=pre[t]; ~i; i=pre[e[i].u]) {
            flow = min(flow, e[i].f);
        }
        max_flow += flow;
        min_cost += flow * dis[t];
        for(int i=pre[t]; ~i; i=pre[e[i].u]) {
            e[i].f -= flow;
            e[i^1].f += flow;
        }
    }

    return make_pair(max_flow, min_cost);
}

int main(int argc, char const *argv[]) {
    int n, m, u, v, c;
    scanf("%d %d", &n, &m);
    Init();
    while(m--) {
        scanf("%d %d %d", &u, &v, &c);
        AddEdge(u, v, 1, c);
        AddEdge(v, u, 1, c);
    }
    AddEdge(0, 1, 2, 0);
    AddEdge(n, n+1, 2, 0);
    printf("%d\n", MinCostMaxFlow(0, n+1).second);
    
    return 0;
}

bLue 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。
本文地址:https://dreamer.blue/blog/post/2016/12/12/poj-2135.dream

还不快抢沙发

添加新评论