poj2135网络流费用入门

来源:互联网 发布:软件总体设计方案 编辑:程序博客网 时间:2024/06/06 03:48

poj2135网络流费用流入门

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

题目部分

  • 题意介绍:
    主人公要从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那个点的费用乘这个路径的最大流量

举个例子就比如坐车,要从a->g,途中要经过转车,每上一次车都要交钱,你一个人从a坐到g要花10块钱,然后你们组团一起坐车,问你一趟要花多少钱(一趟中人数是依据最小的车子能载几个人)。费用流的增广路就是这样,先找到这个路径,在看路径中的最大流量算出这条路径的费用。

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

代码部分

这里输入一条边要建4条边,首先建a->b的有向边,要同时建立反向边,再建b->a的有向边,一样建立反向边。

这里node数组下标要从偶数开始用起,因为底下的增广路那块(也就是+-最小边那里)用到了 ^1 这个技巧,偶数与1异或就会加1,奇数与1异或就会减1。这样如果用正向的边,那么边的下标是偶数,对应的反向边下标就+1就可以找到,如果用的是反向边,那么边的下标是奇数,对应的正向边下标-1就可以找到。

我这里的Node结构体加了个s是这条边的起始点。

#include<iostream>#include<cstring>#include<algorithm>#include<fstream>#include<math.h>#include<algorithm>#include<stack>#include<queue>using namespace std;fstream fin("1.txt");//streambuf *buf = cin.rdbuf(fin.rdbuf());//用于重定项输入改成,把cin当成finconst int inf = 1 << 29;const int MAXN = 1010;const int MAXM = 40010;struct Node{    int s;    int to;    int next;    int capacity;    int value;};int n, m;int index;Node node[MAXM];int head[MAXN];int pre[MAXN];int dis[MAXN];bool vis[MAXN];void init(){    index = 0;    memset(head, -1, sizeof(head));    memset(node, 0, sizeof(node));}void addedge(int a, int b, int v, int c){    node[index].to = b;    node[index].s = a;    node[index].value = v;    node[index].capacity = c;    node[index].next = head[a];    head[a] = index++;    node[index].to = a;    node[index].s = b;    node[index].value = -v;    node[index].capacity = 0;    node[index].next = head[b];    head[b] = index++;}bool spfa(int s, int t, int nnum){    memset(vis, 0, sizeof(vis));    memset(pre, -1, sizeof(pre));    for (int i = 0; i <= nnum; i++)    {        dis[i] = inf;    }    queue<int> que;    que.push(s);    dis[s] = 0;    vis[s] = true;    while (!que.empty())    {        int temp = que.front();        que.pop();        vis[temp] = false;        for (int i = head[temp]; i != -1; i = node[i].next)        {            if (node[i].capacity)            {                int ne = node[i].to;                if (dis[temp] + node[i].value < dis[ne])                {                    dis[ne] = dis[temp] + node[i].value;                    pre[ne] = i;                    if (!vis[ne])                    {                        vis[ne] = true;                        que.push(ne);                    }                }            }        }    }    if (dis[t] == inf)        return false;    return true;}int getMincost(int s, int t, int nnum){    int ans_flow = 0;    int ans_cost = 0;    int temp, minc;    while (spfa(s, t, nnum))    {        temp = t;        minc = inf;        while (pre[temp] != -1)        {            minc = min(node[pre[temp]].capacity, minc);            temp = node[pre[temp]].s;        }        temp = t;        while (pre[temp] != -1)        {            node[pre[temp]].capacity -= minc;            int ss = pre[temp] ^ 1;            node[ss].capacity += minc;            temp = node[pre[temp]].s;        }        ans_cost += dis[t] * minc;    }    return ans_cost;}int main(){    int a, b, v;    int s, t, result;    while (cin >> n >> m)    {        init();        for (int i = 0; i < m; i++)        {            cin >> a >> b >> v;            addedge(a, b, v, 1);            addedge(b, a, v, 1);        }        s = n + 1;        t = s + 1;        addedge(s, 1, 0, 2);        addedge(n, t, 0, 2);        result = getMincost(s, t, t);        cout << result << endl;    }    return 0;}
0 0
原创粉丝点击