uva 10048 Audiophobia

DP(仿照Floyd)

题意:一个无向图,然后多个查询,查询是起点和终点s和t,s到t可能有多条路径,那么每条路径都会有一条权值最大的边,在所有的最大边中找一个最小的,如果s到t之间不连通,那么输出no path

想了很久,大概有两个小时的样子…………然后看了一下数据,刚好最多有100个点,最多10000个查询,那么就给了一个很大的启发,会不会有一个算法会好像dij一样,运行一次能得到做个答案,或者一个算法好像floyd一样,运行一次可以知道所有答案,出于数据的特殊性,我更倾向于往floyd的方向想。

floyd的本质是DP,其实这个问题也很容易发现就是个DP,状态转移方程为

 

max=MAX{ d[i][k] , d[k][j]} 

d[i][j]=MIN{d[i][j] , max}

 

DP思想很容易想到,从i到j,如果经过k点,并且i到k是连通的,k到j是连通的,那么d[i][k]表示i到k的最大值的最小值,d[k][j]表示k到j的最大值的最小值

那么合并两条路径后,最大值的最小值应该是两者中的较大的那个

然后从i到j本身有已有一个最大值的最小值,再比较两者哪个更小,取较小值

当d[i][j]=INF,表示i到j不连通,那么就谈不上什么最大值的最小值

其中初始化d[i][j]=g[i][j]

 

 

#include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f
#define N 110
int d[N][N];
int n,m,mm;
int max(int a ,int b)
{ return a>b?a:b; }
int min(int a, int b)
{ return a<b?a:b; }

void DP()
{
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));
    return ;
}
int main()
{
    int T=0;
    while(scanf("%d%d%d",&n,&m,&mm)!=EOF)
    {
        if(!n && !m && !mm)  break;
        memset(d,0x3f,sizeof(d));
        for(int i=1; i<=m; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            d[u][v]=d[v][u]=w;
        }

        DP();
        T++;
        if(T!=1) printf("\n");
        printf("Case #%d\n",T);
        for(int i=1; i<=mm; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(d[u][v]==INF) printf("no path\n");
            else             printf("%d\n",d[u][v]);
        }
    }
    return 0;
}

 

DP里面的拓展开来可以这样写(方便理解)

if(d[i][k]==INF || d[k][j]==INF)
    continue;
int m;
if(d[i][k]>d[k][j])
    m=d[i][k];
else 
    m=d[k][j];
if(m<d[i][j])
    d[i][j]=m;

 

 

posted @ 2012-12-08 23:08  Titanium  阅读(349)  评论(0编辑  收藏  举报