10048 - Audiophobia (Floyd)

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



你可能感兴趣的:(uva解题报告,动态规划,图论)