[CF1801D] The way home

[CF1801D] The way home

Description

一个人在一张有向图的 \(1\) 号结点,他要去到 \(n\) 结点。每条边 \((a_i,b_i)\) 有边权 \(s_i\),表示走过这条边需要花 \(s_i\) 元。这个人一开始有 \(p\) 元,到了一个点 \(u\),他可以进行若干次演出,每次演出收获 \(w_u\) 元。问到达 \(n\) 的最小演出次数,若无解输出 -1

Solution

首先我们先考虑该题这个人的表演策略,即如果回家的路径确定了,那么我们直接考虑表演的策略。显然有他在某一个点 \(x\) 表演够恰好回到 \(n\) 结点数,而后直接走最小花费的路径回到 \(n\) 结点。接着我们考虑他是如何来到 \(x\) 的,必然有在另一点 \(x'\) 表演够恰好来到 \(x\)。所以我们如果如果已经确定走的路径,那么他的表演策略是确定的。

于是我们考虑先对 \(n\) 个点求出最短路,再用类似贪心的方式求出下次表演的地点。我们考虑在这部分求算中,有两个变量影响,一个是 \(cost_i\) 即到达 \(i\) 点需要表演的次数,和 \(res_i\) 即此时剩余的钱数。显然我们在表演次数取到最小时,使得剩余钱数最多,所以我们考虑使用优先队列维护这样形如堆优化迪杰斯特拉的算法。每次我们取出当前点 \(u\) 时,我们枚举下一个停靠点 \(i\)。则我们可以计算出演唱次数 \(times\)。而后我们比较两种方法优劣性并更新答案,所有答案即为 \(cost_n\)

考虑用类似堆优化迪杰斯特拉实现。注意取整需要考虑被除数为负数的情况,建议手写。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long

int T;
int n,m,p;
const int N=800+7;
vector<pair<int,int>> G[N];
bool vis[N],_vis[N];
int cost[N],res[N];
int dis[N],b[N];

struct node{
	int dis,id;
	friend bool operator < (node a,node b){
		return a.dis>b.dis;
	}
};

struct node2{
	int x,cost,res;
	friend bool operator < (node2 a,node2 b){
		if(a.cost!=b.cost) return a.cost>b.cost;
		return a.res<b.res; 
	}
};

void Dj(int s){
	memset(_vis,0,sizeof _vis);
	priority_queue<node> q;
	memset(dis,80,sizeof dis);
	dis[s]=0;
	q.push({0,s});
	while(!q.empty()){
		int u=q.top().id;
		q.pop();
		if(_vis[u]) continue;
		_vis[u]=1;
		for(auto i:G[u]){
			int k=i.first,w=i.second;
			if(dis[k]>dis[u]+w){
				dis[k]=dis[u]+w;
				q.push({dis[k],k});
			}
		}
	} 
}

//int _ceil(int x,int y){
//	if(x<0)return 0;
//	if(x%y==0)return x/y;
//	return x/y+1;
//}

int _ceil(int x,int y){if(x<0) return 0;return (x+y-1)/y;}
 
void Get_ans(){
	memset(vis,0,sizeof vis);
	priority_queue<node2> q;
	cost[1]=0,res[1]=p;
	q.push((node2){1,cost[1],res[1]});
	while(!q.empty()){
		int u=q.top().x;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		Dj(u);
		for(int i=1;i<=n;i++){
			if(!vis[i]){
//				int times=(int)ceil((dis[i]-res[u])*1.0/b[u]);
					int times=_ceil(dis[i]-res[u],b[u]);
//				printf("times:%lld\n",times);
				node2 tmp={i,cost[u]+times,res[u]+times*b[u]-dis[i]};
				node2 bf={i,cost[i],res[i]};
				if(bf<tmp){
					q.push(tmp);
					cost[i]=tmp.cost;
					res[i]=tmp.res;
				}
			}
		}
	}
}

void solve(){
	scanf("%lld%lld%lld",&n,&m,&p);
	for(int i=1;i<=n;i++){
		G[i].clear();
		scanf("%lld",&b[i]);
		vis[i]=0;cost[i]=0x3f3f3f3f3f3f3f3f;res[i]=0;
	}
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%lld%lld%lld",&u,&v,&w);
		G[u].push_back(make_pair(v,w));
	}
	Dj(1);
//	for(int i=1;i<=n;i++) printf("%d ",dis[i]);
	if(dis[n]==dis[0]) return printf("-1\n"),void();
	Get_ans();
	printf("%lld\n",cost[n]);
}

signed main(){
	cin>>T;
	while(T--) solve();
	return 0;
}
posted @ 2023-07-25 14:20  Zimo_666  阅读(14)  评论(0编辑  收藏  举报