POJ 3268 Silver Cow Party(最短路&Dijkstra)题解

题意:有n个地点,有m条路,问从所有点走到指定点x再走回去的最短路中的最长路径

思路:用Floyd超时的,这里用的Dijkstra。

Dijkstra感觉和Prim和Kruskal的思路很像啊。我们把所有点分为两个集合:S(和源点在同一集合),T(其余点),用dis数组表示每个点到S的最短距离,vis数组记录这个点是否在S中。我们每次找出在T的一个和S距离最短的点,加到S中,这个距离就是他到源点的最短路径(听说能证,我不会证...),然后更新其他点,直到所有点都在S。

这道题从x走回去很简单,就是单源点最短路,但是从某一点走到x的最短路怎么求?遍历?这里有个很妙的方法,就是转置map,然后我们再求一遍x到每个点的最短路径就行了。

代码:

#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 1000+5;
const int INF = 0x3f3f3f3f;
int mp[maxn][maxn];
int dis[maxn];  //和源点集合最短距离
int vis[maxn];  //1则和源点在同一集合内
int n,m,x;
void dijkstra(){
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    dis[x] = 0; //初始化,到自己距离为0
    for(int i = 1;i <= n;i++){
        int Min = INF,k = 0;
        for(int j = 1;j <= n;j++){
            if(!vis[j] && dis[j] < Min){    //找一个和源点集合距离最近的
                Min = dis[j];
                k = j;
            }
        }
        vis[k] = 1;
        for(int j = 1;j <= n;j++){  //更新和源点集合距离
            if(dis[j] > dis[k] + mp[k][j]){
                dis[j] = dis[k] + mp[k][j];
            }
        }
    }
}
void transpose(){
    for(int i = 1;i <= n;i++){
        for(int j =  1;j < i;j++){
            swap(mp[i][j],mp[j][i]);
        }
    }
}
int ans[maxn];
int main(){
    while(scanf("%d%d%d",&n,&m,&x) != EOF){
        memset(mp,INF,sizeof(mp));
        for(int i = 0;i < m;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            mp[u][v] = w;
        }
        dijkstra();
        for(int i = 1;i <= n;i++)
            ans[i] = dis[i];
        transpose();
        dijkstra();
        for(int i = 1;i <= n;i++)
            ans[i] += dis[i];
        int Max = 0;
        for(int i = 1;i <= n;i++)
            Max = max(Max,ans[i]);
        printf("%d\n",Max);
    }
    return 0;
}

 

你可能感兴趣的:(最短路)