SGU 185.Two shortest (最小费用最大流)

时间限制:0.25s

空间限制:4M

题意:

       在n(n<=400)个点的图中,找到并输出两条不想交的最短路。不存在输出“No sulotion”;

 

 

 

 

 


 

Solution:

            最小费用最大流

            建图与poj 2135 一样,添加S到1的流量为2权为0,n到T的流量为2权为0的边,其它边的流量为1,权为路径长度.

            但是这道题麻烦不在要输出最短路,而在仅仅4M的内存上。

            由于只有4M,我们最多存上400*400条边.但是图却是一个无向图,朴素的想法是存上400*400*2条边,但是这里内存不够.

            所以我们首先要确定记录一条边我们是否使用过,如果使用了使用的是那个方向.

            相应的在找到增广路后,把正向反向边的流量改变,把反向边的费用变成负值.

            最后按照我们标记过的边dfs,并输出就好了.

            总的来说是一道足以加深对最小费用最大流的理解的不错的题!

 

参考代码:

/*
       最小费用最大流算法:
       思路:
       以费用为权做最短路算法。
*/
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;
const int INF = 409, Maxn = 0x3f3f3f3f;

struct node {
    int u, v, t, c, next;
} edge[INF * INF];
int head[INF], nCnt = 1;
int G[INF][INF];
void addEdge (int u, int v, int traffic, int cost) {
    edge[++nCnt].v = v, edge[nCnt].u = u, edge[nCnt].t = traffic, edge[nCnt].c = cost;
    edge[nCnt].next = head[u], head[u] = nCnt;
    edge[++nCnt].v = u, edge[nCnt].u = v, edge[nCnt].t = traffic, edge[nCnt].c = cost;
    edge[nCnt].next = head[v], head[v] = nCnt;
}
int max_flow, min_cost;
int n, m, SS, ST, S, T, min_dis = Maxn;
int SPFA() {
    queue<int> ql;
    int vis[INF] = {0}, dis[INF], pre[INF] = {0};
    ql.push (SS);
    memset (dis, 0x3f, sizeof dis);
    vis[SS] = 1, dis[SS] = 0;
    while (!ql.empty() ) {
        int x = ql.front(); ql.pop();
        for (int i = head[x]; i != 0; i = edge[i].next) {
            if (edge[i].t == 0) continue;
            int v = edge[i].v, c = edge[i].c;
            if (dis[v] > dis[x] + c) {
                dis[v] = dis[x] + c;
                pre[v] = i;
                if (!vis[v])
                    ql.push (v), vis[v] = 1;
            }
        }
        vis[x] = 0;
    }
    min_dis = min (min_dis, dis[ST]);
    if (dis[ST] == Maxn) return 0;
    else {
        min_cost += dis[ST];
        int k = pre[ST];
        int cur_flow = Maxn;
        while (k) {
            if (cur_flow > edge[k].t) cur_flow = edge[k].t;
            G[edge[k].u][edge[k].v] = G[edge[k].v][edge[k].u] = 1 ^ G[edge[k].v][edge[k].u];
            edge[k].t = edge[k ^ 1].t, edge[k].c = abs (edge[k].c);
            edge[k ^ 1].t = 0, edge[k ^ 1].c = -abs (edge[k ^ 1].c);
            k = pre[edge[k].u];
        }
        max_flow += cur_flow;
        k = pre[ST];
        while (k) {
            edge[k].t -= cur_flow, edge[k ^ 1].t += cur_flow;
            k = pre[edge[k].u];
        }
        return 1;
    }
}
void dfs (int x) {
    for (int i = head[x]; i != 0; i = edge[i].next) {
        if (G[x][edge[i].v] && edge[i].t > 0 && edge[i].v < T) {
            edge[i].t = 0;
            dfs (edge[i].v);
            break;
        }
    }
    if (x == S) printf ("%d", x);
    else
        printf (" %d", x);
}
int MCMF() {
    while (SPFA() );
    if (max_flow == 2 && min_cost == 2 * min_dis) {
        dfs (T);
        putchar (10);
        dfs (T);
    }
    else
        puts ("No solution");
}
void build() {
    scanf ("%d %d", &n, &m);
    int x, y, z;
    for (int i = 1; i <= m; i++) {
        scanf ("%d %d %d", &x, &y, &z);
        addEdge (x, y, 1, z);
    }
    S = 1, T = n;
    SS = n + 1, ST = n + 2;
    addEdge (SS, S, 2, 0), addEdge (T, ST, 2, 0);
}
int main() {
    build();
    MCMF();
    return 0;
}
View Code

 

posted @ 2014-09-19 21:42  keambar  阅读(234)  评论(0编辑  收藏  举报