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