Farm Tour POJ - 2135(最小费用最大流)

版权声明:转载请标明出处 https://blog.csdn.net/weixin_41190227/article/details/89736104

When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of which contains his house and the Nth of which contains the big barn. A total M (1 <= M <= 10000) paths that connect the fields in various ways. Each path connects two different fields and has a nonzero length smaller than 35,000. 

To show off his farm in the best way, he walks a tour that starts at his house, potentially travels through some fields, and ends at the barn. Later, he returns (potentially through some fields) back to his house again. 

He wants his tour to be as short as possible, however he doesn't want to walk on any given path more than once. Calculate the shortest tour possible. FJ is sure that some tour exists for any given farm.

Input

* Line 1: Two space-separated integers: N and M. 

* Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path's length. 

Output

A single line containing the length of the shortest tour. 

Sample Input

4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2

Sample Output

6

在同一个网络中,可能存在多个总流量相同的最大流,我们可以在计算流量的基础之上,给网络中的弧增加一个单位流量费用(简称费用),在确保流量最大的前提下总费用最小——最小费用最大流。

边权的数据有两个,一个是容量,一个是费用。

主要是两部分,①spfa来求边权(根据费用w)最短路;②在最短路基础上统计计算最小费用的。用spfa求出最短路(其中有个pre[i]数组表示指向i点的边序号),然后再倒序从终点沿着最短路走反向边,找到该最短路上的最小边权——流量。然后再来走一遍,这次需要每次都把最小费用统计一下(+=最小流量*费用),同时从当前边权容量上减去当前流量,以便进入下一次循环的spfa。

题目大意:主人公要从1号走到第N号点,再重N号点走回1号点,同时每条路只能走一次。 
这是一个无向图。输入数据第一行是2个是N和M。N为点的数量,M为路径个数。 
接下来M行是边的数据,每行输入3个数,边的两个端点a,b和边的长度v。 
要你输出来回最短的路径长度。 
题目确保存在来回的不重复路径

解题思路:

这题可以转换成网络流的费用流。

来回并且路径不相同就相当于有用两条从1到N的路径。

把路径长度当成网络流里面每个流的费用,流量都设置成1这样就代表每条路径只能使用1次。增加2个点,源点和汇点,因为来回,就把源点到1建立一条流,流量为2(来回)费用为0,同样N到汇点建立一条流,流量为2费用为0。这样一个网络流就出来了。

这里费用流的增广路径是用spfa来找的,也就是找从源点到汇点流1个单位的流量最小的花费。这题找到路径后就进行正常的网络流增广路了,就是算费用的时候用+=N那个点的费用乘这个路径的最大流量

用spfa不用dijkstra的原因是因为我们建立反向边的时候费用是正向边费用的负数,存在了负权值就不能用dijkstra了。

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

/*
@Author: Top_Spirit
@Language: C++
*/
//#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std ;
typedef long long ll ;
typedef pair < ll, ll > P ;
const int Maxn = 4e4 ;
const int maxn = 2e7 + 10 ;
const int INF = 1 << 30 ;

int n, m, s, t, ans ;
int head[Maxn], cnt ;
int dis[Maxn], vis[Maxn] ;
int pre[Maxn], que[maxn] ;

struct Node {
    int s, to, flow, w, Next ;
}e[maxn];

void addEdge(int u, int v, int w, int flow){
    e[cnt].flow = flow ;
    e[cnt].s = u ;
    e[cnt].to = v ;
    e[cnt].w = w ;
    e[cnt].Next = head[u] ;
    head[u] = cnt++ ;
    e[cnt].flow = 0 ;
    e[cnt].s = v ;
    e[cnt].to = u ;
    e[cnt].w = -w ;
    e[cnt].Next = head[v] ;
    head[v] = cnt++ ;
}

int SPFA() {
    int l, r ;
    memset(pre, -1, sizeof(pre)) ;
    memset(vis, 0, sizeof(vis)) ;
    for (int i = 0; i <= t; i++) dis[i] = INF ;
    dis[s] = 0 ;
    l = 0, r = 0 ;
    que[r++] = s ;
    vis[s] = 1 ;
    while (l < r){
        int u = que[l++] ;
        vis[u] = 0 ;
        for (int i = head[u]; i != -1; i = e[i].Next){
            int v = e[i].to ;
            if (e[i].flow > 0 && dis[v] > dis[u] + e[i].w) {
                dis[v] = dis[u] + e[i].w ;
                pre[v] = i ;
                if (vis[v] == 0) {
                    vis[v] = 1 ;
                    que[r++] = v ;
                }
            }
        }
    }
    if (dis[t] == INF) return 0 ;
    return 1 ;
}

void MCMF(){
    int flow = 0 ;
    while (SPFA()){
//        cout << "+++++" << endl ;
        ans += dis[t] ;
        int u = t ;
        int Min = INF ;
        while (u != s) {
            if (e[pre[u]].flow < Min) Min = e[pre[u]].flow ;
            u = e[pre[u]].s ;
//            cout << "^^^^^" << endl;
        }
        flow += Min ;
        u = t ;
        while (u != s){
            e[pre[u]].flow -= Min ;
            e[pre[u] ^ 1].flow += Min ;
            u = e[pre[u]].s ;
        }
    }
//    cout << "****" << endl ;
}

int main (){
    while (cin >> n >> m){
        s = n + 1 ;
        t = s + 1 ;
        cnt = 0 ;
        memset(head, -1, sizeof(head)) ;
        int u, v, w ;
        for (register int i = 1; i <= m; i++){
            cin >> u >> v >> w ;
            addEdge(u, v, w, 1) ;
            addEdge(v, u, w, 1) ;
        }
        addEdge(s, 1, 0, 2) ;
        addEdge(n, t, 0, 2) ;
        ans = 0 ;
//        cout << "++++" << endl ;
        MCMF() ;
//        cout << "++++" << endl ;
        cout << ans << endl ;
    }
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/weixin_41190227/article/details/89736104