[练习][洛谷1186]最短路 玛丽卡

题目背景
洛谷1186

题目描述
麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。

因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。

在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。

麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。

玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。

编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。

输入格式
第一行有两个用空格隔开的数N和M,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N*(N-1)/2。城市用数字1至N标识,麦克在城市1中,玛丽卡在城市N中。

接下来的M行中每行包含三个用空格隔开的数A,B和V。其中1≤A,B≤N,1≤V≤1000。这些数字表示在A和城市B中间有一条双行道,并且在V分钟内是就能通过。

输出格式
输出文件的第一行中写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。

样例数据
输入

5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10

输出

27

分析:刚开始把m的范围也看成n的范围了,想想觉得O( N2logN )随随便便过啊,so easy!结果,50%……原来是m的范围看错了orz。于是深入想想,其实只有让最短路上的路堵车才能够影响答案(如果有多条最短路,而且有重复部分,那么只有重复部分可以影响答案;如果有多条最短路,而且没有重复部分,那你根本阻止不了玛丽卡23333),所以只需要随便记录一条最短路,枚举路径上的路,因为路最多有N-1条,这才是真O( N2logN )了。

代码
50%:看错范围的后果orz

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;ch>='0'&&ch<='9';ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

int n,m,ans;
int tot,first[1010],nxt[2000010],to[2000010],w[2000010];
int dis[1010];
priority_queue<pair<int,int> > que;

void addedge(int x,int y,int z)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
    w[tot]=z;
    tot++;
    nxt[tot]=first[y];
    first[y]=tot;
    to[tot]=x;
    w[tot]=z;
}

void dijkstra()
{
    memset(dis,0x3f3f3f3f,sizeof(dis));
    dis[1]=0;
    que.push(make_pair(0,1));
    while(!que.empty())
    {
        int u=que.top().second;
        que.pop();
        for(int p=first[u];p;p=nxt[p])
        {
            int v=to[p];
            if(dis[v]>dis[u]+w[p])
            {
                dis[v]=dis[u]+w[p];
                que.push(make_pair(-dis[v],v));
            }
        }
    }
}

int main()
{
    freopen("reve.in","r",stdin);
    freopen("reve.out","w",stdout);

    int x,y,z;
    n=getint(),m=getint();
    for(int i=1;i<=m;++i)   
    {
        x=getint(),y=getint(),z=getint();
        addedge(x,y,z);
    }

    for(int i=1;i<=m;++i)
    {
        z=w[i*2-1];
        w[i*2-1]=0x3f3f3f3f;
        w[i*2]=0x3f3f3f3f;
        dijkstra();
        ans=max(ans,dis[n]);
        w[i*2-1]=z;
        w[i*2]=z;
    }
    cout<<ans<<'\n';
    return 0;
}

100%

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;ch>='0'&&ch<='9';ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

int n,m,ans;
int tot=1,first[1010],nxt[2000010],to[2000010],w[2000010];
int cnt,dis[1010],bian[1010];//tot=1,方便异或找到对边
priority_queue<pair<int,int> > que;

void addedge(int x,int y,int z)
{
    tot++;
    nxt[tot]=first[x];
    first[x]=tot;
    to[tot]=y;
    w[tot]=z;
    tot++;
    nxt[tot]=first[y];
    first[y]=tot;
    to[tot]=x;
    w[tot]=z;
}

void dijkstra()
{
    memset(dis,0x3f3f3f3f,sizeof(dis));
    dis[1]=0;
    que.push(make_pair(0,1));
    while(!que.empty())
    {
        int u=que.top().second;
        que.pop();
        for(int p=first[u];p;p=nxt[p])
        {
            int v=to[p];
            if(dis[v]>dis[u]+w[p])
            {
                dis[v]=dis[u]+w[p];
                que.push(make_pair(-dis[v],v));
            }
        }
    }
}

void dfs(int u)
{
    if(u==1)
        return;

    for(int p=first[u];p;p=nxt[p])
    {
        int v=to[p];
        if(dis[v]==dis[u]-w[p])
        {
            bian[++cnt]=p;
            dfs(v);
            return;
        }
    }
}

int main()
{
    freopen("reve.in","r",stdin);
    freopen("reve.out","w",stdout);

    int x,y,z;
    n=getint(),m=getint();
    for(int i=1;i<=m;++i)
    {
        x=getint(),y=getint(),z=getint();
        addedge(x,y,z);
    }

    dijkstra();//先找最短路
    ans=dis[n];

    dfs(n);//随便找到一条
    for(int i=1;i<=cnt;++i)//把最短路上的边(双向的)赋成极大值,再跑最短路
    {
        z=w[bian[i]];
        w[bian[i]]=0x3f3f3f3f;
        w[bian[i]^1]=0x3f3f3f3f;
        dijkstra();
        ans=max(ans,dis[n]);
        w[bian[i]]=z;//记得还原那条路
        w[bian[i]^1]=z;
    }
    cout<<ans<<'\n';
    return 0;
}

本题结。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值