该题是Floyd算法的一个巧妙变形,虽然AC率很高,但是真正要灵活变化到做出该题,显然要明白Floyd算法的思想和原理 ,弄清楚为什么可以这样更改算法的核心部分。
Floyd算法其实利用了动态规划的思想,适合求解结点不是很多的稠密图 。
我们都知道,动态规划在利用循环嵌套求解时是要规定一个次序的,这样才能将状态成功的转移 。该题的次序就是由k来定义的,从小到大枚举k,定义其意义为i和j之间一点。
那么对于每一个i和j以及每一个k,最优状态就的状态转移方程d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
为什么这样可以表示出每两个点之间的最短路呢? 我们不妨将最短路看成动归中的最优解,那么每一个状态的最优解都是从局部最优解转移过来的,每一个状态都具有相似的子结构 ,所以就可以动态规划出所有的最优解了。
既然知道了其思想核心的动态规划,那么就不难修改了,修改时要注意状态方程所表示的新意义以及状态的转移 。
该题是求最大噪音最小的路径,是不是有点眼熟 ? 没错 ! 还记得第九章例题:《最大面积最小的三角剖分》吗? 如果忘了可以看这里:点击打开链接
该题的思想和那道题如出一辙,所以状态方程即可写出:d[i][j] = min(d[i][j],max(d[i][k],d[k][j]));
细节参见代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
const int INF = 100000000;
int n,m,a,b,c,q,d[maxn][maxn],kase = 0,ok = 0;
void init() {
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) d[i][j] = INF;
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&a,&b,&c);
d[a][b] = d[b][a] = c;
}
}
void Floyd() {
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(d[i][k]!=INF&&d[k][j]!=INF)
d[i][j] = min(d[i][j],max(d[i][k],d[k][j]));
}
int main() {
while(~scanf("%d%d%d",&n,&m,&q)) {
if(!n && !m && !q) return 0;
if(ok) printf("\n");
else ok = 1;
init();
Floyd();
printf("Case #%d\n",++kase);
while(q--) {
scanf("%d%d",&a,&b);
if(d[a][b] == INF) printf("no path\n");
else printf("%d\n",d[a][b]);
}
}
return 0;
}