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

 

你可能感兴趣的:(test)