Light oj-1002 - Country Roads,迪杰斯特拉变形,不错不错~~

                                                                                            1002 - Country Roads
Time Limit: 3 second(s)Memory Limit: 32 MB


I am going to my home. There are many cities and many bi-directional roads between them. The cities are numbered from 0 to n-1 and each road has a cost. There are m roads. You are given the number of my city t where I belong. Now from each city you have to find the minimum cost to go to my city. The cost is defined by the cost of the maximum road you have used to go to my city.

For example, in the above picture, if we want to go from 0 to 4, then we can choose

1)      0 - 1 - 4 which costs 8, as 8 (1 - 4) is the maximum road we used

2)      0 - 2 - 4 which costs 9, as 9 (0 - 2) is the maximum road we used

3)      0 - 3 - 4 which costs 7, as 7 (3 - 4) is the maximum road we used

So, our result is 7, as we can use 0 - 3 - 4.

Input

Input starts with an integer T (≤ 20), denoting the number of test cases.

Each case starts with a blank line and two integers n (1 ≤ n ≤ 500) and m (0 ≤ m ≤ 16000). The next m lines, each will contain three integers u, v, w (0 ≤ u, v < n, u ≠ v, 1 ≤ w ≤ 20000) indicating that there is a road between u and v with cost w. Then there will be a single integer t (0 ≤ t < n). There can be multiple roads between two cities.

Output

For each case, print the case number first. Then for all the cities (from 0 to n-1) you have to print the cost. If there is no such path, print 'Impossible'.

Sample Input

Output for Sample Input

2

 

5 6

0 1 5

0 1 4

2 1 3

3 0 7

3 4 6

3 1 8

1

 

5 4

0 1 5

0 1 4

2 1 3

3 4 7

1

Case 1:

4

0

3

7

7

Case 2:

4

0

3

Impossible

Impossible

Note

Dataset is huge, user faster I/O methods.


    学最短路这么久了竟然漏了这个大水题,哈哈哈哈~~

    做这道题的时候分析了一下样例,题意就是求从t点出发到所有点的所有路径的最小值,千万注意那句话,而这个最小值既是说一整条路径的最长的那条,所有路径中最长的一条再取最短的那条,貌似表述很混乱,不过看样例就可以明白了,那么怎么做呢;

    很明显是一个最短路的变形题,万变不离其宗,方法任意,这里就用dijsktra算法吧,如果从t点出发到不了某个点那么就输出”Impossible“,我们又怎么知道这个点与t点是否联通呢,很简单,用并查集判断一下就好了;

     至于dij算法怎么变形呢,我们就用d[i]来储存从t点出发到i点所有可能路径中的所有最长的线段中最短的那条(本质还是其最短路嘛大笑);再用dijsktra模板打上去,注意在求某点的d[i]时我们需要把d[i]=min(d[i],d[x]+w[x][i])改成d[i]=min(d[i],max(d[x],w[x][i]);前提是x到i之间存在一条路径;这样不就巧妙地解决了问题;具体来看代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=500+10;
int u,v,ww,t,t1,n,m,x,vis[N],f[N],w[N][N],d[N];
int find(int x)
{
    return f[x]==-1?x:f[x]=find(f[x]);
}
void dijsktra()
{
    memset(vis,0,sizeof(vis));
    memset(f,-1,sizeof(f));
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            w[i][j]=i==j?0:INF;
    for(int i=0; i<m; i++)
    {
        scanf("%d%d%d",&u,&v,&ww);
        w[u][v]=w[v][u]=w[u][v]==INF?ww:min(w[u][v],ww);
        int xx=find(u);
        int yy=find(v);
        if(xx!=yy)
            f[xx]=yy;//将所有与定点联通的点连接起来;
    }
    scanf("%d",&x);
    for(int i=0; i<n; i++) d[i]=i==x?0:INF;
    for(int i=0; i<n; i++)
    {
        int xx=0,m=INF;
        for(int j=0; j<n; j++)
            if(!vis[j]&&d[j]<=m)
                m=d[xx=j];
        vis[xx]=1;
        for(int j=0; j<n; j++)
            if(!vis[j]&&w[xx][j]!=INF)
                d[j]=min(d[j],max(d[xx],w[xx][j]));
    }
    printf("Case %d:\n",t1-t);
    int xx=find(x);
    for(int i=0; i<n; i++)
    {
        if(find(i)==xx)//如果联通则输出;
            printf("%d\n",d[i]);
        else
            printf("Impossible\n");
    }
}
int main()
{
    scanf("%d",&t);
    t1=t;
    while(t--)
    {
        dijsktra();
    }
    return 0;
}

后来发现,其实可以不用并查集的,因为如果与T点不连通则它们之间不存在路径,则距离为INF,所以输出判断一下即可: 代码看起来很短的样子,就是喜欢用最简洁的方法解决最复杂的问题

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=500+10;
int u,v,ww,t,t1,n,m,x,vis[N],w[N][N],d[N];
void dijsktra()
{
    memset(vis,0,sizeof(vis));
    for(int i=0; i<n; i++) d[i]=i==x?0:INF;
    for(int i=0; i<n; i++)//注意d[i]储存的值的含义;
    {
        int xx=0,m=INF;
        for(int j=0; j<n; j++)
            if(!vis[j]&&d[j]<=m)
                m=d[xx=j];说明到xx点的最短路已经求出来了;
        vis[xx]=1;
        for(int j=0; j<n; j++)
            if(!vis[j]&&w[xx][j]!=INF)//说明xx与j点之间存在通路;
                d[j]=min(d[j],max(d[xx],w[xx][j]));//一条可能路径的最长的那条与其他路径的最长的那条进行比较;
    }
    printf("Case %d:\n",t1-t);
    for(int i=0; i<n; i++)
    {
        if(d[i]!=INF)//如果不连通则之间的路长为INF,以此为判断依据;
            printf("%d\n",d[i]);
        else
            printf("Impossible\n");
    }
}
int main()
{
    scanf("%d",&t);
    t1=t;
    while(t--)
    {
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            w[i][j]=i==j?0:INF;
    for(int i=0; i<m; i++)
    {
        scanf("%d%d%d",&u,&v,&ww);
        w[u][v]=w[v][u]=w[u][v]==INF?ww:min(w[u][v],ww);
    }
    scanf("%d",&x);
        dijsktra();
    }
    return 0;
}
完美!!!                      如有更好的方法或者思路,恭请指教!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值