10048 - Audiophobia (Floyd)

来源:互联网 发布:手机编程用什么软件 编辑:程序博客网 时间:2024/06/10 04:27

该题是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;}



1 0