poj2135

题意:给定一个无向图,要从1点到n点再返回1点,每条边最多走一次,问最短需要走多远。

分析:最小费用最大流,把题意看成是要找两条无交集的从1到n的路线,使距离和最小。图中的点和边就是网络流图中的点和边。设置一个源,接到1点,设置一个汇,从n点接到汇。为保证无交集,我们把每条边的流量设置为1,而源发出的流量和汇接收的流量均为2。每条边的费用就是该边在原图中的权值。

注意:有重边,所以要用邻接表。因为是无向图,所以要在加边时,原图中的一条边要变成网络流图中的两条边(如果把反向负权费用边也算上就总共4条边)。

由于最短路算法是最小费用最大流算法的子算法,所以有些最短路的题可能要用到最小费用最大流。

View Code
#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

using namespace std;



#define typef int

#define typec int

#define maxn 1005

#define maxm 10005

#define N maxn + 2

#define E maxm * 4 + 4

const typef inff = 0x3f3f3f3f;

const typec infc = 0x3f3f3f3f;



struct network

{

    int nv, ne, pnt[E], nxt[E];

    int vis[N], que[N], head[N], pv[N], pe[N];

    typef flow, cap[E];

    typec cost, dis[E], d[N];

    void addedge(int u, int v, typef c, typec w)

    {

        pnt[ne] = v;

        cap[ne] = c;

        dis[ne] = +w;

        nxt[ne] = head[u];

        head[u] = (ne++);

        pnt[ne] = u;

        cap[ne] = 0;

        dis[ne] = -w;

        nxt[ne] = head[v];

        head[v] = (ne++);

    }

    int mincost(int src, int sink)

    {

        int i, k, f, r;

        typef mxf;

        for (flow = 0, cost = 0;;)

        {

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

            memset(vis, 0, sizeof(vis));

            for (i = 0; i < nv; ++i)

                d[i] = infc;

            d[src] = 0;

            pv[src] = src;

            vis[src] = 1;

            for (f = 0, r = 1, que[0] = src; r != f;)

            {

                i = que[f++];

                vis[i] = 0;

                if (N == f)

                    f = 0;

                for (k = head[i]; k != -1; k = nxt[k])

                    if (cap[k] && dis[k] + d[i] < d[pnt[k]])

                    {

                        d[pnt[k]] = dis[k] + d[i];

                        if (0 == vis[pnt[k]])

                        {

                            vis[pnt[k]] = 1;

                            que[r++] = pnt[k];

                            if (N == r)

                                r = 0;

                        }

                        pv[pnt[k]] = i;

                        pe[pnt[k]] = k;

                    }

            }

            if (-1 == pv[sink])

                break;

            for (k = sink, mxf = inff; k != src; k = pv[k])

                if (cap[pe[k]] < mxf)

                    mxf = cap[pe[k]];

            flow += mxf;

            cost += d[sink] * mxf;

            for (k = sink; k != src; k = pv[k])

            {

                cap[pe[k]] -= mxf;

                cap[pe[k] ^ 1] += mxf;

            }

        }

        return cost;

    }

    void build(int v, int e)

    {

        nv = v;

        ne = 0;

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

        int x, y;

        typec w;

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

        {

            scanf("%d%d%d", &x, &y, &w);

            addedge(x, y, 1, w);// add arc (u->v, f, w)

            addedge(y, x, 1, w);

        }

        addedge(0, 1, 2, 0);

        addedge(v - 2, v - 1, 2, 0);

    }

} g;



int n, m;



int main()

{

    //freopen("t.txt", "r", stdin);

    scanf("%d%d", &n, &m);

    g.build(n + 2, m);

    printf("%d\n", g.mincost(0, n + 1));

    return 0;

}

你可能感兴趣的:(poj)