最短路 稠密图 —— 传递闭包

题目链接

题目描述:

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

输入描述:

输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

输出描述:

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

样例输入

2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

样例输出:

3
2

由题可知,点少线多,所以可以优先考虑 稠密图 ,用 传递闭包 即可通过。先上代码,后序还有 传递闭包 的证明哦。
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 101;
const int inf = 0x3f3f3f3f;

int dp[N][N];

int main() {
    int n, m, x, y, k;
    while(scanf("%d%d", &n, &m), n != 0) {
        memset(dp, inf, sizeof(dp));
        for(int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &x, &y, &w);
            dp[x][y] = dp[y][x] = w;
        }
        for(int i = 1; i <= n; ++i) dp[i][i] = 0;
        // 传递闭包的三重循环
        for(int k = 1; k <= n; ++k) 
            for(int i = 1; i <= n; ++i) 
                for(int j = 1; j <= n; ++j) 
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
        printf("%d\n", dp[1][n]);
    }
    return 0;    
} 

另外我想借此来证明一下 传递闭包 的正确性。证:

传递闭包是三重循环结构,其分别是 枚举过渡点、枚举起点、枚举终点(起点和终点可以看做一体),但是你有没有考虑过 先枚举起点、终点, 再枚举过渡点(方案二) 是否正确呢, 接下来我们就具体的证明一下这两种方案的正确性:
我们首先需要建立一个模型(起点和终点固定,枚举过渡点),如图:
在这里插入图片描述通过 枚举过渡点 来更新路径(减少起点到终点路径中的过渡点(当某条路径中的过渡点个数为零时 更新起点到终点的距离))
(说明:方案一,先确定过渡点,枚举起点和终点,再枚举过渡点
方案二,先确定起点和终点,枚举过渡点,再枚举起点和终点)

单轮这个模型,我们就能判断出方案二是错误的,因为在枚举上侧路径中的过渡点时,无法更新路径,而这个模型适合方案一。
最后我们把这个基础的模型通过变换和嵌套就可以得到一个图,反之一个图可以拆解为多个这样的模型,所以可证方案一是适合一个图的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章