[AtCoder Beginner Contest 164] -E - Two Currencies (分层最短路)
Problem Statement
There are NN cities numbered 11 to NN, connected by MM railroads.
You are now at City 11, with 1010010100 gold coins and SS silver coins in your pocket.
The ii-th railroad connects City UiUi and City ViVi bidirectionally, and a one-way trip costs AiAi silver coins and takes BiBi minutes. You cannot use gold coins to pay the fare.
There is an exchange counter in each city. At the exchange counter in City ii, you can get CiCi silver coins for 11 gold coin. The transaction takes DiDi minutes for each gold coin you give. You can exchange any number of gold coins at each exchange counter.
For each t=2,...,Nt=2,...,N, find the minimum time needed to travel from City 11 to City tt. You can ignore the time spent waiting for trains.
Constraints
- 2≤N≤502≤N≤50
- N−1≤M≤100N−1≤M≤100
- 0≤S≤1090≤S≤109
- 1≤Ai≤501≤Ai≤50
- 1≤Bi,Ci,Di≤1091≤Bi,Ci,Di≤109
- 1≤Ui<Vi≤N1≤Ui<Vi≤N
- There is no pair i,j(i≠j)i,j(i≠j) such that (Ui,Vi)=(Uj,Vj)(Ui,Vi)=(Uj,Vj).
- Each city t=2,...,Nt=2,...,N can be reached from City 11 with some number of railroads.
- All values in input are integers.
题意:
现在一个\(\mathit n\)个节点\(\mathit m\)条边的双向图,你现在在节点\(\text 1\),拥有\(\mathit S\)个银币,每一条边有两个信息\(A_i,B_i\)分别代表经过这条边需要花费的银币数量和需要的时间长度,每一个节点拥有两个信息\(C_i,D_i\)代表在第\(\mathit i\)个节点可以花费长度为\(D_i\)的时间获得\(C_i\)个银币。
问从节点\(\text 1\)到节点\(2,3,\dots , n\)分别需要的最小时间长度。
思路:
分层最短路经典的题目,分层最短路是类似动态规划的思想应用在图论最短路上的算法。
设\(dp[i][j]\)代表到第\(\mathit i\)个节点还剩余\(\mathit j\)个银币时的最小花费。
由于题目的数据范围限制:\(1 \leq A_i \leq 50\),那么\(N*A_{max}\)不超过\(2500\),即我们最多只需要不超过\(2500\)个银币就可以走遍全图,所以DP数组的大小为\(dp[N][N*A_{max}]\)。
然后正常的\(dijkstra\)算法跑单源最短路,在每一个节点\(\mathit i\)枚举花了\(k*D_i\)时间获得\(k*C_i\)个银币,遇到剩余银币个数大于\(N*A_{max}\)时,将其变为\(N*A_{max}\)即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <unordered_map>
// #include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 110;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
ll dp[55][55 * 50];
struct edge
{
ll id, t, val, rm;
edge() {}
edge(ll ff, ll tt, ll vv, ll rrm)
{
id = ff;
t = tt;
val = vv;
rm = rrm;
}
bool operator < (const edge & bb) const
{
return val > bb.val;
}
};
priority_queue<edge> q;
ll n, m, s;
ll a[maxn];
ll b[maxn];
ll c[maxn];
ll d[maxn];
std::vector<edge> E[maxn];
ll maxcost;
void dij()
{
maxcost = n * 50;
s = min(s, maxcost);
repd(i, 1, n)
{
repd(j, 0, maxcost) {
dp[i][j] = 1e18;
}
}
dp[1][s] = 0;
q.push(edge(0, 1, 0, s));
edge temp;
while (!q.empty())
{
temp = q.top();
q.pop();
for (auto &y : E[temp.t])
{
ll rm = temp.rm - a[y.id];
ll cost = temp.val + b[y.id];
int flag = 0;
for (; rm <= maxcost; )
{
if (rm >= 0)
{
if (dp[y.t][rm] > cost)
{
dp[y.t][rm] = cost;
q.push(edge(0, y.t, dp[y.t][rm], rm));
}
}
cost += d[temp.t];
rm += c[temp.t];
if (rm > maxcost && !flag)
{
flag = 1;
rm = maxcost;
}
}
}
}
}
int main()
{
#if DEBUG_Switch
freopen("C:\\code\\input.txt", "r", stdin);
#endif
//freopen("C:\\code\\output.txt","r",stdin);
n = readint();
m = readint();
s = readint();
int u, v;
repd(i, 1, m)
{
u = readint();
v = readint();
a[i] = readint();
b[i] = readint();
E[v].pb(edge(i, u, 0, 0));
E[u].pb(edge(i, v, 0, 0));
}
repd(i, 1, n)
{
c[i] = readint();
d[i] = readint();
}
dij();
repd(i, 2, n)
{
ll ans = 1e18;
repd(j, 0, maxcost)
{
ans = min(ans, dp[i][j]);
}
printf("%lld\n", ans );
}
return 0;
}