最大流的魅力--zju 2760

  忙碌了以下午,终于在吃饭之前过了这道题,很水的一道题,悲剧的是我看错了题。。。。。。

  最大流的用处真的很广,只要数学模型建的好,最大流就会变成解决问题的犀利武器,这道题让求两点之间所有的最短路的数目,涉及到了两个知识点:

  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的时候,不要求到队列为空,只要找到汇点就跳出,有的时候会省很多时间!

你可能感兴趣的:(最大流)