SCU - 4444 Travel
暴力分类讨论233333.
肯定要先分 a<=b 和 a>b 两种情况讨论啊QWQ
对于第一种情况,肯定是优先走a的边。
如果1和n有边的话,那么答案直接就是a;
否则,答案就是 b 和 只走a到n的最短路 中的 更小值。
对于第二种情况,肯定是优先走b的边。
如果1和n有边的话,那么答案肯定直接就是b;
否则,如果所有2~n-1的点都要么和1有a边要么和n有a边,那么答案就是a (因为不管怎么走都要经过a边)。
否则答案就是 min(2*b,a) ,分别代表走一个既不和1有边又不和n有边的点中转,或者直接从1走到n。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+5; inline int read(){ int x=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x; } int hd[N],ne[N*10],to[N*10],A,B,d[N],n,m,num; ll ans; inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;} inline void bfs(){ memset(d,0,sizeof(d)); queue<int> q; int x; d[1]=1,q.push(1); while(!q.empty()){ x=q.front(),q.pop(); for(int i=hd[x];i;i=ne[i]) if(!d[to[i]]){ d[to[i]]=d[x]+1,q.push(to[i]); } } } inline bool ck1(){ for(int i=hd[1];i;i=ne[i]) if(to[i]==n) return 1; return 0; } inline bool ck2(){ for(int i=2,now;i<n;i++){ now=0; for(int j=hd[i];j;j=ne[j]) if(to[j]==1||to[j]==n){ now=1; break;} if(!now) return 1; } return 0; } int main(){ while(scanf("%d%d%d%d",&n,&m,&A,&B)==4){ fill(hd+1,hd+n+1,0),num=0,ans=1e18; for(int i=1,uu,vv;i<=m;i++){ uu=read(),vv=read(); add(uu,vv),add(vv,uu); } if(A<=B){ ans=B,bfs(); if(d[n]) ans=min(ans,(d[n]-1)*(ll)A); } else{ if(!ck1()) ans=B; // 1和n 在A图中不连通 else if(!ck2()) ans=A; // 没有一个点 和1和n相连的边都是B边 // (也就是任意一条1到n的路径都至少要经过一条A边) else ans=min(B<<1,A); // 可以找到一个中转点使得它到1和n都是B边 } printf("%lld\n",ans); } return 0; }
我爱学习,学习使我快乐