Atcoder Beginner Contest 164 E Two Currencies(拆点+最短路)

Posted et2006

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Atcoder Beginner Contest 164 E Two Currencies(拆点+最短路)相关的知识,希望对你有一定的参考价值。

题目链接

题意:有 (n) 个城市,它们由 (m) 条双向道路连接,保证它们能够彼此到达。第 (i) 条道路连接 (u_i,v_i),需要花费 (x_i) 个银币,耗费 (t_i) 秒的时间。每个城市处都有兑换银币处,第 (i) 个城市中你可以用 (1) 个金币兑换 (c_i) 个银币,可以兑换无限次,不过兑换 (1) 次需要花费 (d_i) 秒的时间。你一开始在 (1) 号城市,有 (s) 个银币和无限多的金币,求到其它城市需要耗费的最小时间。
(1 leq n leq 50)(1 leq x_i leq 50)(1 leq t_i,d_i leq 10^9)(1 leq s,c_i leq 10^9)

abc 的 F 都切不掉,只好水 E 的题解了
观察到虽然 (s,c_i) 很大,但是 (x_i) 只有 (50)。这也就意味着到其它需要花费的银币绝对不会超过 (49 imes 50=2450),所以如果当前银币数超过 (2450),就可以将它看作 (2450)
我们将“当前位于城市 (i),手中有 (j) 个银币”看成一个点 ((i,j)),那么我们可以重新建一张图,两个状态 ((x_1,y_1),(x_2,y_2)) 之间有一条有向边当且仅当 ((x_1,y_1)) 可以到达 ((x_2,y_2)),边权为花费的时间。
建图:

  • ((i,j) ightarrow (i,j+c_i)),边权为 (d_i)
  • ((i,j) ightarrow (k,j-x_p)),边权为 (t_p),其中 ((i,k)) 之间有边,编号为 (p)(j geq x_p)
    跑一遍 dijkstra,起点为 ((1,s)),点 (u) 的答案就是 (min (1,s))((u,i)) 的距离。
    大概是网络流基本建图模型?(雾
#include <bits/stdc++.h>
using namespace std;
#define fi			first
#define se			second
#define fz(i,a,b)	for(int i=a;i<=b;i++)
#define fd(i,a,b)	for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a)		a.begin(),a.end()
#define giveup(...) return printf(__VA_ARGS__),0;
#define fill0(a)	memset(a,0,sizeof(a))
#define fill1(a)	memset(a,-1,sizeof(a))
#define fillbig(a)	memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define mask(a)		(1ll<<(a))
#define maskx(a,x)	((a)<<(x))
#define _bit(a,x)	(((a)>>(x))&1)
#define _sz(a)		((int)(a).size())
#define filei(a)	freopen(a,"r",stdin);
#define fileo(a)	freopen(a,"w",stdout);
#define fileio(a) 	freopen(a".in","r",stdin);freopen(a".out","w",stdout)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define put(x)		putchar(x)
#define eoln        put(‘
‘)
#define space		put(‘ ‘)
#define y1			y_chenxiaoyan_1
#define y0			y_chenxiaoyan_0
#define int long long
typedef pair<int,int> pii;
inline int read(){
	int x=0,neg=1;char c=getchar();
	while(!isdigit(c)){
		if(c==‘-‘)	neg=-1;
		c=getchar();
	}
	while(isdigit(c))	x=x*10+c-‘0‘,c=getchar();
	return x*neg;
}
inline void print(int x){
	if(x<0){
		putchar(‘-‘);
		print(abs(x));
		return;
	}
	if(x<=9)	putchar(x+‘0‘);
	else{
		print(x/10);
		putchar(x%10+‘0‘);
	}
}
inline int qpow(int x,int e,int _MOD){
	int ans=1;
	while(e){
		if(e&1)	ans=ans*x%_MOD;
		x=x*x%_MOD;
		e>>=1;
	}
	return ans;
}
int n=read(),m=read(),s=read(),c[55],d[55];
struct edge{
	int u,v,w;
	edge(){/*ycxakioi*/}
	edge(int _u,int _v,int _w){
		u=_u;v=_v;w=_w;
	}
};
const int MAGIC=2456;
inline int id(int x,int y){
	return x*(MAGIC+1)+y;
}
vector<edge> g[55*2555];
int dist[55*2555],vis[25*2555];
priority_queue<pii,vector<pii>,greater<pii> > q;
signed main(){
	fz(i,1,m){
		int u,v,a,b;cin>>u>>v>>a>>b;
		fz(j,0,MAGIC){
			if(j>=a){
				g[id(u,j)].push_back(edge(id(u,j),id(v,j-a),b));
				g[id(v,j)].push_back(edge(id(v,j),id(u,j-a),b));
			}
		}
	}
	fz(i,1,n)	c[i]=read(),d[i]=read();
	fz(i,1,n){
		fz(j,0,MAGIC-1){
			int cur=j+c[i];
			if(cur>=MAGIC){
				g[id(i,j)].push_back(edge(id(i,j),id(i,MAGIC),d[i]));
			}
			else{
				g[id(i,j)].push_back(edge(id(i,j),id(i,cur),d[i]));
			}
		}
	}
	fillbig(dist);
	dist[id(1,min(s,MAGIC))]=0;
	q.push({0,id(1,min(s,MAGIC))});
	while(!q.empty()){
		pii p=q.top();q.pop();
		int sum=p.fi,x=p.se;
		if(sum>dist[x])	continue;
		foreach(it,g[x]){
			int y=it->v,z=it->w;
			if(dist[y]>dist[x]+z){
				dist[y]=dist[x]+z;
				q.push({dist[y],y});
			}
		}
	}
	fz(i,2,n){
		int mn=0x3f3f3f3f3f3f3f3fll;
		fz(j,0,MAGIC)	mn=min(mn,dist[id(i,j)]);
		cout<<mn<<endl;
	}
	return 0;
}

以上是关于Atcoder Beginner Contest 164 E Two Currencies(拆点+最短路)的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242