AtCoder Beginner Contest 164E - Two Currencies (二维最短路)
Posted aaronchang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 164E - Two Currencies (二维最短路)相关的知识,希望对你有一定的参考价值。
https://atcoder.jp/contests/abc164/tasks/abc164_e
题意大概是有n个城市,m条无向边,初始状态下,位于1号城市,且初始有s个银币。从u点到v点需要花费a银币、b时间。在每个点可以花d时间去兑换c个银币,求从起点1到各个点需要的最短时间。
思路:很显然这是一个单源最短路问题,我设计数组dis[i][j]表示,到达i城市还剩下j银币的最短时间。由于n的范围是2~50,且a的范围是1~50,那么从1号城市出发最多花费2500银币即可到达任意城市,那么初始的dis数组j维度最大就是2500.
然后去跑一个普通的dij最短路,队列中存储的状态是{城市i,当前剩下的银币}。
对于可以到达的城市,有转移状态 dis[y][w - b] = dis[cur][w] + dis(cur,v) (其中w是当前位于cur城市所剩下的银币,b为转移到y城市的银币花费数,那么转移到y城市就是w-b了)
对于每一个可以到达的城市,也可以选择取钱,d[cur][min(w + c[cur],(ll)2500)] = d[cur][w] + t[cur],t数组为取钱的花费时间。对于每一个城市和当前在这个城市所剩下的银币数,这种状态也需要压入队列中去,然后去转移,整体来讲很像dp的思想。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 55; 5 int n,m,tot; 6 ll dis[maxn][2600],c[maxn],t[maxn]; 7 ll s; 8 int head[maxn]; 9 struct node 10 { 11 int to,next; 12 ll w,cost; 13 }e[maxn*maxn]; 14 void add(int u,int v,ll w,ll c){ 15 e[tot].to = v; 16 e[tot].w = w; 17 e[tot].cost = c; 18 e[tot].next = head[u]; 19 head[u] = tot++; 20 } 21 void dijkstra(ll s,ll d[][2600]){ 22 queue<pair<int,ll> > q; 23 int vis[n+5][2600]; 24 for(int i = 1;i<=n;i++){ 25 for(int j = 0;j<=2500;j++) dis[i][j] = 0x3f3f3f3f3f3f3f3f,vis[i][j] = 0; 26 } 27 d[1][s] = 0; 28 q.push({1,s}); 29 while(!q.empty()){ 30 int cur = q.front().first; 31 ll w = q.front().second; 32 q.pop(); 33 //if(vis[cur][w]) continue; 34 //vis[cur][w] = 1; 35 for(int i = head[cur];~i;i = e[i].next){ 36 int y = e[i].to; 37 ll a = e[i].w,b = e[i].cost; 38 if(w>=b && d[y][w - b] > d[cur][w] + a ){ 39 d[y][w-b] = d[cur][w] + a; 40 q.push({y,w-b}); 41 } 42 } 43 if(d[cur][min(w + c[cur],(ll)2500)]> d[cur][w] + t[cur]){ 44 d[cur][min(w + c[cur],(ll)2500)] = d[cur][w] + t[cur]; 45 q.push({cur,min(w + c[cur],(ll)2500)}); 46 } 47 } 48 } 49 int main(){ 50 scanf("%d%d%lld",&n,&m,&s); 51 s = min(s,(ll)2500); 52 for (int i = 0; i <=n; ++i) head[i] = -1; 53 /* code */ 54 for (int i = 0; i <m; ++i) 55 { 56 int u,v;ll a,b; 57 scanf("%d%d%lld%lld",&u,&v,&a,&b); 58 add(u,v,b,a); 59 add(v,u,b,a); 60 /* code */ 61 } 62 for(int i = 1;i<=n;i++){ 63 scanf("%lld%lld",&c[i],&t[i]); 64 } 65 dijkstra(s,dis); 66 for(int i = 2;i<=n;i++){ 67 ll ans = 0x3f3f3f3f3f3f3f3f; 68 for(int j = 0;j<=2500;j++) ans = min(ans,dis[i][j]); 69 printf("%lld ",ans); 70 } 71 return 0; 72 }
以上是关于AtCoder Beginner Contest 164E - Two Currencies (二维最短路)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 115 题解