SCU 4444 Travel (完全图 最短路 set )

思路:

首先考虑a小于等于b,那么我们只需要跑一边由a边建的图就好了,因为原图是完全图,所以得到的结果和b取最小值就好。
然后考虑a大于b,进行一遍bfs,注意每个点最多计算一次,所以我们可以用两个set集合来标记这个点还能不能用(能用的话用set.count(v)=1来表示),如果此时某个能用的点这次因为有a边而不能用了,那么把这个点放进另一个set:ts,这个集合是下次可以接着用的点。

总之卡点是bfs,dijsktra直接板子。
话说这个bfs写的是真好(不是夸自己,从dalao那偷来的想法2333
(话说读书人的事怎么能叫偷2333

#include <iostream>
#include <cstdio>
#include <queue>
#include <set>
#include <string.h>
#include <algorithm>
#define inf 0x3f3f3f3f
typedef long long int lli;
using namespace std;
const int mod = 1e9+7;

const int maxn = 102000;
struct edge{
    int to,v,next;
    edge(){}
    edge(int tt,int vv){to=tt,v=vv;}
    bool operator < (const edge&b) const {
        return v>b.v;
    }
}ed[1200000];
int head[maxn],cnte;
bool vis[maxn];
lli dis[maxn];

void ae(int x,int y,int v){
    ed[++cnte].to = y;
    ed[cnte].v = v;
    ed[cnte].next = head[x];
    head[x] = cnte;
}

void dij(int s){
    priority_queue<edge> q;
    int now = head[s];
    memset(dis,0x3f,sizeof(dis));
    while(now != -1){
        dis[ed[now].to] = ed[now].v;
        q.push(ed[now]);
        now = ed[now].next;
    }
    vis[s] = true;
    dis[s] = 0;
    int pos;
    while(!q.empty()){
        pos = q.top().to;
        now = head[pos];
        while(vis[pos] == false && now != -1){
            int v = ed[now].to;
            if(dis[v] > dis[pos]+ed[now].v){
                dis[v] = dis[pos]+ed[now].v;
                q.push(edge(ed[now].to,dis[v]));
            }
            now = ed[now].next;
        }
        vis[pos] = true;
        q.pop();
    }
}

int n,m,a,v1,v2;lli b;



set<int>st,ts;
set<int>::iterator it;
lli bfs(int a,int b){
    dis[n]=inf;
    queue<int> q;int u;
    st.clear(); ts.clear();
    for(int i=2;i<=n;i++){
        st.insert(i);
    }
    dis[1] = 0;q.push(1);
    while(!q.empty()){
        u = q.front();q.pop();
        for(int i = head[u];~i;i=ed[i].next){
            int v = ed[i].to;
            if(st.count(v)==1){
                st.erase(v);ts.insert(v);
            }
        }
        for(it=st.begin();it!=st.end();it++){
            dis[*it] = dis[u] + 1;
            q.push(*it);
        }
        st=ts;
        ts.clear();
    }
    return dis[n]*b<a ? dis[n]*b:a;
}


int main(){
    while(~scanf("%d%d%d%lld",&n,&m,&a,&b)){
        memset(head,-1,sizeof(head));cnte = 0;
        memset(vis,false,sizeof(vis));
        int flag = 0;
        for(int i = 1;i <= m;i++){
            scanf("%d%d",&v1,&v2);
            ae(v1,v2,a);ae(v2,v1,a);
        }
        lli ans;
        if(a <= b){
            dij(1);
            ans = min(dis[n],b);
        }
        else{
            ans = bfs(a,b);
        }
        printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值