ZOJ 2760 How Many Shortest Path(最短路径+最大流)

求解非重叠最短路径
本文介绍了一种利用Floyd算法与网络流技术解决有向加权图中源点到汇点间非重叠最短路径数量的方法。通过Floyd算法找到所有节点间的最短路径,并将符合条件的路径加入网络流图中,最后利用Dinic算法求得最大流即为所求路径数量。

Description

Given a weighted directed graph, we define the shortest path as the path who has the smallest length among all the path connecting the source vertex to the target vertex. And if two path is said to be non-overlapping, it means that the two path has no common edge. So, given a weighted directed graph, a source vertex and a target vertex, we are interested in how many non-overlapping shortest path could we find out at most.

Input

Input consists of multiple test cases. The first line of each test case, there is an integer number N (1<=N<=100), which is the number of the vertices. Then follows an N * N matrix, represents the directed graph. Each element of the matrix is either non-negative integer, denotes the length of the edge, or -1, which means there is no edge. At the last, the test case ends with two integer numbers S and T (0<=S, T<=N-1), that is, the starting and ending points. Process to the end of the file.

Output

For each test case, output one line, the number of the the non-overlapping shortest path that we can find at most, or "inf" (without quote), if the starting point meets with the ending.

 

题目大意:一有向有权图,给源点、汇点,问从源点到汇点有多少条不重叠(没有重边)的最短路径

思路:一次floyd,把dis[s][i] + edge[i][j] + dis[j][t] == dis[s][t]的边(最短路径上的边)都加入网络流的图,容量为1。最大流为答案(容量为1,那么这些从源点出发的流都不会有重叠边)。

PS:据说矩阵的对角线上的点不都是0,我把AC代码上的mat[i][i] = st[i][i] = 0注释掉了,果然WA了,这是闹哪样……当然要是你不使用类似于[i][i]这种边就不会有这种烦恼……

 

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int MAXN = 110;
const int MAXE = MAXN * MAXN * 2;
const int INF = 0x7f7f7f7f;

struct Dinic {
    int n, m, st, ed, ecnt;
    int head[MAXN];
    int cur[MAXN], d[MAXN];
    int to[MAXE], next[MAXE], flow[MAXE], cap[MAXE];

    void init(int ss, int tt, int nn) {
        st = ss; ed = tt; n = nn;
        ecnt = 2;
        memset(head, 0, sizeof(head));
    }

    void add_edge(int u, int v, int c) {
        to[ecnt] = v; cap[ecnt] = c; flow[ecnt] = 0; next[ecnt] = head[u]; head[u] = ecnt++;
        to[ecnt] = u; cap[ecnt] = 0; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++;
    }

    bool bfs() {
        memset(d, 0, sizeof(d));
        queue<int> que; que.push(st);
        d[st] = 1;
        while(!que.empty()) {
            int u = que.front(); que.pop();
            for(int p = head[u]; p; p = next[p]) {
                int v = to[p];
                if(!d[v] && cap[p] > flow[p]) {
                    d[v] = d[u] + 1;
                    que.push(v);
                    if(v == ed) return true;
                }
            }
        }
        return d[ed];
    }

    int dfs(int u, int a) {
        if(u == ed || a == 0) return a;
        int outflow = 0, f;
        for(int &p = cur[u]; p; p = next[p]) {
            int v = to[p];
            if(d[u] + 1 == d[v] && (f = dfs(v, min(a, cap[p] - flow[p]))) > 0) {
                flow[p] += f;
                flow[p ^ 1] -= f;
                outflow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        return outflow;
    }

    int Maxflow() {
        int ans = 0;
        while(bfs()) {
            for(int i = 0; i <= n; ++i) cur[i] = head[i];
            ans += dfs(st, INF);
        }
        return ans;
    }
} G;

int mat[MAXN][MAXN];
int st[MAXN][MAXN];

#define REP(i, t) for(int i = 1; i <= t; ++i)

void floyd(int n) {
    REP(k, n) REP(i, n) REP(j, n) {
        if(st[i][k] == -1 || st[k][j] == -1) continue;
        if(st[i][j] == -1 || st[i][j] > st[i][k] + st[k][j]) st[i][j] = st[i][k] + st[k][j];
    }
    //REP(i, n) REP(j, n) printf("%d\n", st[i][j]);
}

int main() {
    int n, s, t;
    while(scanf("%d", &n) != EOF) {
        REP(i, n) REP(j, n) {
            scanf("%d", &mat[i][j]);
            st[i][j] = mat[i][j];
        }
        REP(i, n) st[i][i] = mat[i][i] = 0;
        scanf("%d%d", &s, &t);
        ++s, ++t;
        if(s == t) {
            printf("inf\n");
            continue;
        }
        floyd(n);
        G.init(s, t, n);
        REP(i, n) REP(j, n)
            if(i != j && mat[i][j] != -1 && st[s][i] != -1 && st[j][t] != -1
               && st[s][t] == st[s][i] + mat[i][j] + st[j][t]) G.add_edge(i, j, 1);
        printf("%d\n", G.Maxflow());
    }
}

  

转载于:https://www.cnblogs.com/oyking/p/3235509.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值