find the longest of the shortest HDU1595

**题意:**Marica 要去 Mirko 所在的城市。从 Marica 所在城市到 Mirko 所在城市的所有道路中有一条路坏了不能走,但是除去这条坏的路 Marica 还是能够到达 Mirko 所在城市。Marica 总是会走最短路线,现在 Mirko 想知道最坏情况下 Marica 多长时间到达自己所在的城市。

思路:既然是最坏情况,那么坏掉的那条路就一定是最短路径中一段。因为 Marica 总是会走最短路线,所以枚举删除原最短路径中的其中一条边,再去求此时起点到终点的最短路径。这些删除原最短路径中一条边后求得的最短路径中的最大值就是答案。

这道题的题意比较难懂,懂了之后思路就不难get到了,思路对了实现对了就行了。这种难度的题目要多练练才行。
代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF = 1000000;
const int MAXN = 1010;

int N,M;
int G[MAXN][MAXN];
int d[MAXN];
int pro[MAXN];
bool vis[MAXN];

void Dijkstra(int s, bool flag) //这里的flag用来标志是否需要更新路径
{
    for(int i=1; i<=N; i++) d[i] = INF;
    memset(vis, false, sizeof(vis));
    if(flag) memset(pro, 0, sizeof(pro));
    d[s] = 0;
    if(flag) pro[s] = s;

    for(int i=1; i<=N; i++){
        int x, m = INF;
        for(int j=1; j<=N; j++){
            if(!vis[j] && d[j] < m){
                m = d[x=j];
            }
        }

        vis[x] = true;

        for(int j=1; j<=N; j++){
            if(!vis[j] && d[j] > d[x]+G[x][j]){
                d[j] = d[x] + G[x][j];
                if(flag) pro[j] = x;  //如果flag 为 true, 则需要记录路径
            }
        }
    }
}

void Init()
{
    for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
            G[i][j] = INF;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d%d", &N, &M) == 2){
        Init();
        while(M--){
            int a,b,c;
            scanf("%d%d%d", &a, &b, &c);
            G[a][b] = G[b][a] = c;
        }

        Dijkstra(1, true);  //在没删边时跑一次得到最短路径

        int t = N;
        int ans = -1;
        while(t != 1){   //遍历最短路径上的每段路,跑出这段路坏掉的情况下的最短路
            int tmp = G[t][pro[t]];
            G[t][pro[t]] = G[pro[t]][t] = INF;
            Dijkstra(1, false);
            ans = max(ans, d[N]);
            G[t][pro[t]] = G[pro[t]][t] = tmp;
            t = pro[t];
        }

        printf("%d\n", ans);
    }

    return 0;
}

用优先权队列实现的版本如下:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF = 1000000;
const int MAXN = 1010;

struct Node{
    int v,w;
    Node(){}
    Node(int a, int b):v(a), w(b){}
    bool operator < (const Node& n)const{
        return w > n.w;
    }
};

int N,M;
int G[MAXN][MAXN];
int d[MAXN];
int pro[MAXN];
bool vis[MAXN];

void Dijkstra(int s, bool flag) //这里的flag用来标志是否需要更新路径
{
    for(int i=1; i<=N; i++) d[i] = INF;
    memset(vis, false, sizeof(vis));
    if(flag) memset(pro, 0, sizeof(pro));
    d[s] = 0;
    if(flag) pro[s] = s;

    priority_queue<Node> que;
    que.push(Node(s, 0));

    while(!que.empty()){
        Node tmp = que.top(); que.pop();
        vis[tmp.v] = true;
        for(int i=1; i<=N; i++){
            if(!vis[i] && d[i] > d[tmp.v]+G[tmp.v][i]){
                d[i] = d[tmp.v] + G[tmp.v][i];
                if(flag) pro[i] = tmp.v;  //如果flag 为 true, 则需要记录路径
                que.push(Node(i, d[i]));
            }
        }
    }
}

void Init()
{
    for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
            G[i][j] = INF;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d%d", &N, &M) == 2){
        Init();
        while(M--){
            int a,b,c;
            scanf("%d%d%d", &a, &b, &c);
            G[a][b] = G[b][a] = c;
        }

        Dijkstra(1, true);  //在没删边时跑一次得到最短路径

        int t = N;
        int ans = -1;
        while(t != 1){   //遍历最短路径上的每段路,跑出这段路坏掉的情况下的最短路
            int tmp = G[t][pro[t]];
            G[t][pro[t]] = G[pro[t]][t] = INF;
            Dijkstra(1, false);
            ans = max(ans, d[N]);
            G[t][pro[t]] = G[pro[t]][t] = tmp;
            t = pro[t];
        }

        printf("%d\n", ans);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值