『Luogu 1186』玛丽卡 (枚举 + SPFA)

题目链接

题目描述

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

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

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

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

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

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



解题思路

挺简单的一道题:

我们首先最暴力的方法就是枚举每一条边,然后跑一遍\(SPFA\),显然这样得T到飞起,m最大是\(\frac {n \times (n-1)}{2}\),炸到姥姥家去了,对吧qwq。

稍微想想就发现,其实我们不需要美剧所有的边,因为有的边根本不会给最短路带来任何的影响,我们只需要枚举最短路上的边就好。

最短路的边数最大是\(n-1\),跑这么多遍\(SPFA\),复杂度比较玄学qwq,堆优化一下更保险。

ps:假如最短路不止有一条呢? 同理,我们先钦定一条路径,那我们枚举不在这条路上的边时,对答案是没有任何影响的,我们还是只用枚举最短路上的边就好了。



代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=500500;
int n,m,cnt=0;
int head[maxn<<1],ne[maxn<<1],to[maxn<<1],v[maxn<<1],dis[maxn],fr[maxn],num[maxn];
bool nok[maxn<<1],vis[maxn];
struct nod{
    int x;
};
inline bool operator < (nod a,nod b){
    return dis[a.x]>dis[b.x];
}
inline void add(int f,int t,int w){
    ne[++cnt]=head[f],head[f]=cnt,to[cnt]=t,v[cnt]=w;
}
priority_queue<nod>q;
inline int SPFA(bool xx){
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    while(!q.empty())q.pop();
    vis[1]=1,dis[1]=0,q.push((nod){1});
    while(!q.empty()){
        nod now=q.top();
        q.pop();
        vis[now.x]=0;
        for(register int i=head[now.x];i;i=ne[i]){
            if(nok[i])continue;
            if(dis[to[i]]>dis[now.x]+v[i]){
                dis[to[i]]=dis[now.x]+v[i];
                if(xx){
                    fr[to[i]]=now.x;
                    num[to[i]]=i;
                }
                if(!vis[to[i]]){
                    vis[to[i]]=1;
                    q.push((nod){to[i]});
                }
            }
        }
    }
    return dis[n];
}
int main(){
    scanf("%d%d",&n,&m);
    for(register int i=1,a,b,c;i<=m;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c),add(b,a,c);
    }
    SPFA(1);
    int now=n,ans=0;
    while(now!=1){
        int tmp=num[now];
        if(tmp&1)tmp++;
        else tmp--;
        nok[tmp]=nok[num[now]]=1;
        SPFA(0);
        ans=max(ans,dis[n]);
        nok[tmp]=nok[num[now]]=0;
        now=fr[now];
    }
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/Fang-Hao/p/9710684.html