忙碌了以下午,终于在吃饭之前过了这道题,很水的一道题,悲剧的是我看错了题。。。。。。
最大流的用处真的很广,只要数学模型建的好,最大流就会变成解决问题的犀利武器,这道题让求两点之间所有的最短路的数目,涉及到了两个知识点:
1.如何判断一条边是否在最短路上,floyd定理给出了计算方法:一条边v(i,j)是从s到t的最短路径上的边当且仅当G[s,i]+W[i,j]+G[j,t]=G[s,t],G[x,y]表示x到y的最短路径,w[i,j]表示v(i,j)这条边的权值。
2..如何计算不相交的最短路径数,其实很简单,把所有的在最短路径上的边提出来建一个网络图,边权为1,因为权值为1,所以求源点到终点的最大流就可得到答案。
代码如下:
代码
1 #include<stdio.h>
2 #include<string.h>
3 #include<queue>
4 #include<iostream>
5 using namespace std;
6 #define INF 0x7fffffff
7 #define MM 11000
8 #define NN 110
9
10 int map[NN][NN],f[NN][NN],n,len;
11 int c[NN][NN],pre[NN],T,S;
12 int Min(int a, int b){
13 return a < b ? a : b;
14 }
15 void add(int x,int y,int v)
16 {
17 c[x][y] = v;
18 }
19 int bfs()
20 {
21 int start = 0, end = 1,i,j,k;
22 int que[NN],max[NN]; bool visit[NN];
23 memset(visit,false,sizeof(visit));
24 que[0] = S; visit[S] = true; max[S] = INF;
25 while (start < end){
26 int t = que[start++];
27 for (i = 0; i< n; i++){
28 if (c[t][i] > 0 && visit[i] == false){
29 que[end++] = i; visit[i] = true; pre[i] = t;
30 max[i] = Min(max[t],c[t][i]);
31 if (i == T) return max[i];
32 }
33 }
34 }
35 return -1;
36 }
37 int dinic()
38 {
39 int ans = 0,f; pre[S] = -1;
40 while ((f = bfs()) != -1){
41 ans += f;
42 int j = T,i = pre[T];
43 while (i != -1){
44 c[i][j] -= f;
45 c[j][i] += f;
46 j = i; i = pre[j];
47 }
48 }
49 return ans;
50 }
51 void init()
52 {
53 int i,j;
54 //idx = 0;
55 memset(c,0,sizeof(c));
56 // for (i = 0; i < n; i++) Link[i] = 0;
57 for (i = 0; i < n; i++)
58 for (j = 0; j< n; j++)
59 if (i != j && f[i][j] != INF && map[S][i] + f[i][j] + map[j][T] ==len)
60 add(i,j,1);
61 printf ("%d\n",dinic());
62 }
63 int bfs_len()
64 {
65 queue<int> q; q.push(S);
66
67 int i,j,k,dis[NN];
68 memset(dis,-1,sizeof(dis));
69 dis[S] = 0;
70 while (!q.empty()){
71 int t = q.front(); q.pop();
72 for (i = 0; i< n; i++)
73 if (map[t][i] != INF)
74 if (dis[i] == -1 || dis[i] > dis[t] + map[t][i]){
75 q.push(i); dis[i] = dis[t] + map[t][i];
76 }
77
78 }
79 return dis[T];
80 }
81 void floyd()
82 {
83 int i,j,k;
84 for (k = 0; k < n; k++)
85 for (i = 0; i< n; i++)
86 if (map[i][k] != INF)
87 for (j = 0; j< n; j++)
88 if (map[k][j] != INF)
89 map[i][j] = Min(map[i][j],map[i][k] + map[k][j]);
90 }
91 int main()
92 {
93 int i,j;
94 while (scanf ("%d",&n) != EOF){
95 for (i = 0; i< n; i++)
96 for (j = 0; j < n; j++){
97 scanf ("%d",&map[i][j]);
98 if (map[i][j] == -1)
99 map[i][j] = INF;
100 f[i][j] = map[i][j];
101 }
102 for (i = 0; i< n; i++) map[i][i] = 0;
103 scanf ("%d%d",&S,&T);
104 if (S == T) {printf ("inf\n"); continue;}
105 len = bfs_len();
106 if (len == -1) {printf ("0\n"); continue;}
107 floyd(); init();
108 }
109 return 0;
110 }
注意:数据量小的稠密图用邻接矩阵来求有很大的优势,并且BFS的时候,不要求到队列为空,只要找到汇点就跳出,有的时候会省很多时间!