WuKong (Floyd + dp)

WuKong

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 223 Accepted Submission(s): 95
 
Problem Description
Liyuan wanted to rewrite the famous book “Journey to the West” (“Xi You Ji” in Chinese pinyin). In the original book, the Monkey King Sun Wukong was trapped by the Buddha for 500 years, then he was rescued by Tang Monk, and began his journey to the west. Liyuan thought it is too brutal for the monkey, so he changed the story:

One day, Wukong left his home - Mountain of Flower and Fruit, to the Dragon   King’s party, at the same time, Tang Monk left Baima Temple to the Lingyin Temple to deliver a lecture. They are both busy, so they will choose the shortest path. However, there may be several different shortest paths between two places. Now the Buddha wants them to encounter on the road. To increase the possibility of their meeting, the Buddha wants to arrange the two routes to make their common places as many as possible. Of course, the two routines should still be the shortest paths.

Unfortunately, the Buddha is not good at algorithm, so he ask you for help.
 
Input
There are several test cases in the input. The first line of each case contains the number of places N (1 <= N <= 300) and the number of roads M (1 <= M <= N*N), separated by a space. Then M lines follow, each of which contains three integers a b c, indicating there is a road between place a and b, whose length is c. Please note the roads are undirected. The last line contains four integers A B C D, separated by spaces, indicating the start and end points of Wukong, and the start and end points of Tang Monk respectively. 

The input are ended with N=M=0, which should not be processed.
 
Output
Output one line for each case, indicating the maximum common points of the two shortest paths.
 
Sample Input
6 6
1 2 1
2 3 1
3 4 1
4 5 1
1 5 2
4 6 3
1 6 2 4
0 0
 
Sample Output
3

Hint: One possible arrangement is (1-2-3-4-6) for Wukong and (2-3-4) for Tang Monk. The number of common points are 3.
 
 
Source
2009 Multi-University Training Contest 2 - Host by TJU 
 
Recommend
gaojie

题意:给你一个无向图,给出孙悟空的出发地点和目的地点,唐僧的出发地点和目的地地点,问你如果他俩都走最短路的情况下(如果某个人有多条最短路的时候,那么这个人会走相遇点最多的那条),最多可以有多少个相遇的地方。
  这一题首先需要先求出两者的最短路,因为这里的点不是很多只有300个,所以可以用Flyod先求出多源最短路,同时需要求出某两点之间的最短路最多有多少个点。为什么需要求某两点最多有多少个点?这里经过分析可以得出,如果两条最短路有相交的部分,那么这些相交的部分一定是连续的。为什么呢?这里的分析和dij的分析一样。因为求最短路的时候对于某一个点延伸出去的时候是选最短的那条路,所以如果该点是重合点,那么如果还有重合点,那就意味着有一段最短路同时存在于两条最短路之间,所以如果我们求最短路的时候顺便把两点之间最短路最多经过了多少个点,那么只要我们枚举两条最短路中间的那一段就可以找到目标的最大值。
  求某两点的最短路最多有多少段的状态转移方程:
dp[i][j] = max(dp[i][j], dp[i][u] + dp[u][j] ).                         然后因为求得是点到点的最大距离,所以随后结果要+1;


如果路径(x,y)是a->b的最短路径中的一段,则min(a,b) = min(a,x) + min(x,y) + min(y,b) 最后只需找到同时在两条最短路径上,且距离最长的那一段


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int INF = 0xFFFFFF;
int n, m;
int map[305][305];
int dp[305][305];
void floyd() {
    for (int u = 1; u <= n; ++u) {
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (map[i][j] > map[i][u] + map[u][j]) {
                    dp[i][j] = dp[i][u] + dp[u][j];
                    map[i][j] = map[i][u] + map[u][j];
                } else if (map[i][j] == map[i][u] + map[u][j]) {
                    dp[i][j] = max(dp[i][u] + dp[u][j], dp[i][j]);
                }
            }
        }
    }
}
int main() {
    while (cin >> n >> m && (n + m)) {
        
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j) {
                if (i == j)
                    map[i][j] = 0;
                else
                    map[i][j] = INF;
                dp[i][j] = 0;
            }
        for (int i = 0; i < m; ++i) {
            int a, b, c;
            cin >> a >> b >> c;
            if (map[a][b] > c) {
                map[a][b] = map[b][a] = c;
                dp[a][b] = dp[b][a] = 1;
            }
        }
        int A, B, C, D;
        cin >> A >> B >> C >> D;
        floyd();
        int ans = -1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (ans < dp[i][j] && map[A][i] + map[i][j] + map[j][B] == map[A][B] && map[C][i] + map[i][j] + map[j][D] == map[C][D]) {
                    ans = dp[i][j];
                }
            }
        }
        cout << ans + 1 << endl;
        
    }
}



 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值