poj2135 最小费用最大流入门题

题意:给定n个点(编号1~n),有m条无向边。再给出m条边的信息,起点,终点和距离。现在从1走到n,再从n走回1,没条边只能走一次,求这样走的最短路径。

将边权作为费用,流量为1(每条边只能走一次)。再新建一个源点s,s到1有一条指向1的有向边,边权为0,流量为2,再建一个汇点t,有一条从n指向t的有向边,边权为0,流量为2。建图完毕,跑费用流

最小费用:距离最短,最大流==2(来回)。
(1)距离为费用,用spfa找一条存在流量的从源点到汇点的最短路dis[t]
(2)若存在,则处理出这条上能增加的最大流量flow,然后正向边-flow,反向边+flow。
(3)ans += dis[t]*flow;
(4)重复(1)~(3)

#include 
#include 
#include 
#include 

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1010;
const int M = 40010;
int dis[N],pre[N];
bool vis[N];
int from[M],to[M],val[M],capacity[M],nxt[M];
int head[N],tot;
int n, m;

void addedge(int u, int v, int w, int c)
{
    ++tot;
    from[tot] = u;
    to[tot] = v;
    val[tot] = w;
    capacity[tot] = c;
    nxt[tot] = head[u];
    head[u] = tot;
    ++tot;
    from[tot] = v;
    to[tot] = u;
    val[tot] = -w;
    capacity[tot] = 0;
    nxt[tot] = head[v];
    head[v] = tot;
}

bool spfa(int s, int t, int cnt)
{
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    for(int i = 1; i <= cnt; ++i) dis[i] = INF;
    vis[s] = 1, dis[s] = 0;
    queue <int> q;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = nxt[i])
            if(capacity[i])
            {
                int v = to[i];
                if(dis[u]+val[i] < dis[v])
                {
                    dis[v] = dis[u]+val[i];
                    pre[v] = i;
                    if(!vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
    }
    return dis[t] != INF;
}

int getmincost(int s, int t, int cnt)
{
    int cost = 0;
    while(spfa(s, t, cnt))
    {
        int pos = t, flow = INF;//每次增加的流量
        while(pre[pos] != -1)
        {
            flow = min(flow, capacity[pre[pos]]);
            pos = from[pre[pos]];
        }
        pos = t;
        while(pre[pos] != -1)
        {
            capacity[pre[pos]] -= flow;
            capacity[pre[pos]^1] += flow;
            pos = from[pre[pos]];
        }
        cost += dis[t]*flow;
    }
    return cost;
}

int main()
{
    while(~scanf("%d %d", &n, &m))
    {
        memset(head, -1, sizeof(head));
        tot = -1;
        for(int i = 1; i <= m; ++i)
        {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            addedge(u, v, w, 1);
            addedge(v, u, w, 1);
        }
        int s = n+1, t = n+2;
        addedge(s, 1, 0, 2);
        addedge(n, t, 0, 2);
        printf("%d\n", getmincost(s, t, t));
    }
    return 0;
}

你可能感兴趣的:(网络流)