该题是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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-10 04:57:13