洛谷 3393 逃離僵屍島
阿新 • • 發佈:2018-08-31
所有 影響 set tro scanf struct 註意 答案 ongl
題目戳這裏
一句話題意
貌似一句話講不清楚,麻煩大家自己看一下題意吧
Solution
本來是沒有必要謝這篇博客的,但是為了紀念一下這個提交了15遍的題目和一個傻逼錯誤,還是寫一下吧。
step1:首先以所有的淪陷點做bfs,處理出危險城市(權值為Q)和安全城市(權值為P)。
step2:跑spfa,註意邊權為兩端點權值之和,輸出答案時除以二即可。(洛谷題解中kkk沒有給出正確性的證明,在這裏補充一下:其實以道路指向的點權為邊權值也可以,但因為1和n的權值為0,並不影響結果,所以路徑上所有的點權都被計算了兩遍,再除2就是正確答案)。
step3:輸出dis[n]/2即可。
註意事項:
1.要開longlong。
2.在第一步操作進行完後,淪陷點需要重新復制INF,因為可能會被當做危險點所以權值賦成Q(坑了很久,一直沒有發現)。
3.註意1和n權值都為0,並且INF的值要賦大一點。
Coding
#include<bits/stdc++.h> using namespace std; const int N = 100005; const long long INF = 1e15; struct road { int to,next; }e[N*5]; long long cnt,head[N],cost[N],n,m,k,s,die[N],P,Q; long long a,b,dis[N],vis[N],Use[N],date[N]; void add(long long x,long long y) { cnt++; e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } void search() { memset(date,0,sizeof(date)); queue<int> q; for (int i=1;i<=k;i++) { q.push(die[i]); Use[die[i]]=1; date[die[i]]=0; } while(!q.empty()) { int u=q.front();q.pop(); if(date[u]==s) continue; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(!Use[v]) { Use[v]=1; q.push(v); date[v]=date[u]+1; } } } } queue<long long> q; void SPFA(long long root) { for(int i=1;i<=n;i++) dis[i]=INF; vis[root]=1; q.push(root); dis[root]=0; while(!q.empty()) { long long u=q.front(); vis[u]=0; q.pop(); for(int i=head[u];i!=0;i=e[i].next) { long long v=e[i].to; if(dis[v]>dis[u]+cost[u]+cost[v]) { dis[v]=dis[u]+cost[v]+cost[u]; if(!vis[v]) q.push(v),vis[v]=1; } } } } int main() { cin>>n>>m>>k>>s; cin>>P>>Q; for(int i=1;i<=k;i++) scanf("%lld",&die[i]); for(int i=1;i<=m;i++) { scanf("%lld%lld",&a,&b); add(a,b); add(b,a); } search(); for (int i=1;i<=n;i++) { if(Use[i] == 1) cost[i] = Q; else cost[i] = P; } for(int i=2;i<n;i++) if(cost[i]==0) cost[i]=P; for(int i=1;i<=k;i++) cost[die[i]]=INF; cost[1]=0; cost[n]=0; SPFA(1); cout<<dis[n]/2; return 0; }
洛谷 3393 逃離僵屍島