Why so serious? --[NKU]schindlerlee

2010年02月10日星期三.sgu185 dijkstra + 流

2010年02月10日星期三.sgu185
ALGO:dijkstra + 流
求两条没有相同边的最短路。
直觉的想法是求一条,然后把这条相关的删掉,再求另外一条
但是这种想法是不正确的。

引用
http://www.answeror.com/archives/28474 的一组数据来说明这个问题
6 7
1 2 1
1 3 1
2 4 1
3 4 1
3 5 1
4 6 1
5 6 1

如果第一次求出的最短路是1-3-4-6, 那么第二条最短路就不存在了, 但是实际上有两条最短路,
即1-3-5-6和1-2-4-6.
所以需要调整,调整的思想让我们想到了流。

保留图中所有能构成任何一条最短路的边,将所有边的容量设为1.  然后对这个图求两次增广路。
由于容量的限制,所以求得的两条最短路一定是没有公共边的,这时按照流的方向,输出这两条
路径即可。

注意:不要按照增广时的顶点顺序输出最短路,这样是不对的,同样可以使用上面的那组数据,
如果先增广的是 1-3-4-6这条路径的话,那么输出的结果就会不正确了。 我就是这么wa@test 20 好久的。

  1 
  2 const int N = 401;
  3 const int inf = 1 << 20;
  4 int dis[N],vis[N],n,m;
  5 int g1[N][N],g2[N][N],p[N],f[N][N];
  6 
  7 bool dijkstra()
  8 {
  9   int i,j,k;
 10   memset(vis,0,sizeof(vis));
 11   dis[1= 0,vis[1= true;
 12   for (i = 2;i <= n;i++) {
 13       dis[i] = g1[1][i];
 14   }
 15   for (k = 2;k <= n;k++) {
 16       int min = inf,idx = 1;
 17       for (i = 2;i <= n;i++) {
 18           if (dis[i] < min && !vis[i]) {
 19               min = dis[i],idx = i;
 20           }
 21       }
 22       if (idx == 1) { break; }
 23       vis[idx] = true;
 24       for (i = 1;i <= n;i++) {
 25           if (dis[i] > min + g1[idx][i]) {
 26               dis[i] = min + g1[idx][i];
 27           }
 28       }
 29   }
 30   for (i = 1;i <= n;i++) {
 31       for (j = 1;j <= n;j++) {
 32           if (dis[i] + g1[i][j] == dis[j]) {
 33               g2[i][j] = 1;
 34           }
 35       }
 36   }
 37   return dis[n] != inf;
 38 }
 39 
 40 bool bfs()
 41 {
 42   memset(vis,0,sizeof(vis));
 43   memset(p,0,sizeof(p));
 44   queue<int> que;
 45   que.push(1),vis[1= true;
 46   while (!que.empty()) {
 47       int u = que.front(); que.pop();
 48       for (int v = 2;v <= n;v++) {
 49           if (!vis[v] && g2[u][v]) {
 50               p[v] = u,vis[v] = true;
 51               if (v == n) {
 52                   for (v = n;v != 1;v = p[v]) {
 53                       u = p[v];
 54                       g2[u][v] --;
 55                       g2[v][u] ++;
 56                       if (f[v][u] > 0) {
 57                           f[v][u]--;
 58                       }else {
 59                           f[u][v] ++;
 60                       }
 61                   }
 62                   return true;
 63               }
 64               que.push(v);
 65           }
 66       }
 67   }
 68   return false;
 69 }
 70 
 71 void pr(int u)
 72 {
 73   if (u == n) {
 74       printf("%d\n",u);
 75       return;
 76   }
 77   for (int i = 1;i <= n;i++) {
 78       if (f[u][i] > 0) {
 79           f[u][i] --;
 80           printf("%d ",u);
 81           pr(i);
 82           return ;
 83       }
 84   }
 85 }
 86 
 87 bool EK()
 88 {
 89   if (bfs() && bfs()) {
 90       pr(1), pr(1);
 91       return true;
 92   }
 93   return false;
 94 }
 95 
 96 
 97 int main()
 98 {
 99   int i,j,a,b,c;
100   scanf("%d%d",&n,&m);
101   for (i = 1;i <= n;i++) {
102       for (j = 1;j <= n;j++) {
103           g1[i][j] = inf;
104       }
105   }
106   for (i = 0;i < m;i++) {
107       scanf("%d%d%d",&a,&b,&c);
108       if (g1[a][b] > c) {
109           g1[a][b] = g1[b][a] = c;
110       }
111   }
112   if (!dijkstra() || !EK()){
113       printf("No solution\n");
114   }
115   return 0;
116 }
117 


posted on 2010-02-10 01:51 schindlerlee 阅读(1355) 评论(0)  编辑 收藏 引用 所属分类: 解题报告


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理