变形最短路 SCU 4444 training 3

  1. 题意转自http://blog.csdn.net/lvshubao1314/article/details/48848319
  2. SCU - 4444 别样最短路径-大数据完全图 
  3. 题目大意:给定一个完全图,其中有两种边,长度为a(不超过5e5)或长度为b(剩下的),求有1~n的最短路径(数据范围1e5) 
  4. 解题思路:如果1和n之间连边为a那么答案一定为a和一条最短的全由b组成的路径的较小者,如果1和n之间连边为b,那么答案一定 
  5.            为b和一条最短的全由a组成的路径的较小者。对于第1种情况直接跑spfa就可以了,第二种情况由于边数较多,不能直接spfa 
  6.            从1开始搜索与其相连的边权为b的边,用set维护一下,由于每个点只入队1次,复杂度还是允许的。这种处理方法还是第一 
  7.            次做,感觉很巧妙 

分析:  自己比赛的时候也大概想到了对于公路的讨论,,但是不会表示。也感觉太复杂了,,

在bfs中
其实这个地方的set就相当于vis数组一样,,但是如果用vis的话,我就要从1~n遍历,显然会超时,所以用set  ,这样遍历就不用扫那么多点。。。(也许这只是套路,学会就行)

#include<bits/stdc++.h>
#define ll long long
#define sf scanf
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
const long long INF=1e17;
int n,m;
ll a,b;
const int maxn=5*1e5+5;
ll d[maxn];
set<int>st,ts;
set<int>::iterator it;
struct Edge{
    int v,nxt;
}edge[maxn*2];
int tol;
int vis[maxn];
int head[maxn];
void addedge(int u,int v){
    edge[tol].v=v;edge[tol].nxt=head[u];
    head[u]=tol++;
}
void init(){
    tol=0;
    mem(vis,0);
    mem(head,-1);
}
void bfs(){
    queue<int>q;st.clear();ts.clear();
    q.push(1);
    for(int i=2;i<=n;++i){
        d[i]=INF;
        st.insert(i);
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];~i;i=edge[i].nxt){
            int v=edge[i].v;
            if(st.count(v)==0)continue;
            st.erase(v);ts.insert(v);
        }
        for(it=st.begin();it!=st.end();it++){
            q.push(*it);
            d[*it]=d[u]+1;
        }
        st.swap(ts);//其实st和 ts就相当于 vis的作用,用来标记哪些点有没走过
        ts.clear();
    }
    printf("%lld\n",min(d[n]*b,a));
}
void spfa(){
    mem(vis,0);
    queue<int>q;
    q.push(1);
    vis[1]=1;
    d[1]=0;
    for(int i=2;i<=n;++i)d[i]=INF;
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].v;
            if(d[v]>d[u]+1){
                d[v]=d[u]+1;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    printf("%lld\n",min(d[n]*a,b));
}
int main(){
    while(~scanf("%d%d%d%d",&n,&m,&a,&b)){
        init();
        int fg=0;
        for(int i=1;i<=m;++i){
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
            if(u==1&&v==n||u==n&&v==1)fg=1;
        }
        if(fg)bfs();
        else spfa();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值