Bicycles(变形dijkstra,动态规划思想)

Codeforces Round 918 (Div. 4)

G. Bicycles


G. Bicycles

题意:

斯拉夫的所有朋友都打算骑自行车从他们住的地方去参加一个聚会。除了斯拉维奇,他们都有一辆自行车。他们可以经过 n n n 个城市。他们都住在城市 1 1 1 ,想去参加位于城市 n n n 的聚会。城市地图可以看作一个无向图,有 n n n 个节点和 m m m 条边。边 i i i 连接城市 u i u_i ui 和 v i v_i vi ,长度为 w i w_i wi 。

斯拉夫没有自行车,但他有的是钱。每个城市都有一辆自行车出售。在 i i i 这个城市中,自行车的速度系数为 s i s_{i} si 。一旦斯拉维奇买了一辆自行车,他就可以在任何时候 用它从他现在所在的城市前往任何邻近的城市,只需花费 w i ⋅ s j w_i \cdot s_j wi⋅sj 时间,因为他是在用自己拥有的自行车 j j j 穿越边缘 i i i 。

斯拉维奇想买多少辆自行车都可以,因为钱对他来说不是问题。由于斯拉维奇不喜欢骑自行车旅行,他希望在最短的时间内从他的住处到达聚会地点。由于他的信息技能很生疏,他需要你的帮助。

斯拉夫从城市 1 1 1 到城市 n n n 所需的最短时间是多少?斯拉夫没有自行车就无法旅行。保证斯拉夫可以从城市 1 1 1 到达其他任何城市。

思路:

很好的一个变型dijkstra。先放一下dijkstra的证明过程:

写的很抽象,但是证明思路很明显:如果我们从堆里所有状态中选出走过的路长度最少的状态,如果这个状态所在位置之前还没有被访问过,那么现在这个状态走过的路长度就是最短的,我的意思是,之后到达这个位置的最短路径就再也不可能被刷新了。证明是显然的:现在所有状态走过的路的长度都大于这个状态,我们继续走下去只会使得走的路变长,无论从什么状态来推,之后到达的时候长度一定不可能小于现在的长度了。

一眼看下来感觉应该是个最短路问题,用dijkstra,但是由于我们可以先去一个其他城市买到一个更快的车子,然后用这个车子到达终点,结果可能更优,所以直接跑dij是不对的。

考虑到我们到一个城市的时候只看原点到它的距离,而不看手上的自行车是有可能不优的。但是如果多存储一维自行车的慢速因子来描述我们到这个城市的距离就是最优的了。具体来说,原本的 d i s dis dis 数组设为 d i s u b i k e disubike disubike ,表示到达城市 u u u,手上最快的自行车为 b i k e bike bike 的最短距离,这样 u , b i k e u,bike u,bike 确定时,距离一定是越小越好的,而不会对后面产生影响。

做法就出来了。 d i s dis dis 数组多描述一维自行车的慢速因子,优先队列存储的状态多存储一个手上最快的自行车的信息就可以了。这里因为我们自行车一定是会越来越快的,而我们经过的点最长是,先到一个城市买最快的自行车,再回来走到终点,因此时间复杂度差不多是 O ( 2 n m l o g n ) O(2nmlogn) O(2nmlogn) 的。

到达某个点,带有某个自行车的最近距离,这里其实很像动态规划的思想。不如说,dijkstra本身就很有动态规划的味道。比较类似的有这里的E题

code:

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=1005;
const ll inf=1e9;

int T,n,m;

int head[maxn],counter;
struct EDGE{
	int v,w,nxt;
}e[maxn<<1];
void adde(int u,int v,int w){
	e[++counter].v=v;
	e[counter].w=w;
	e[counter].nxt=head[u];
	head[u]=counter;
}
void init(){
	cin>>n>>m;
	memset(head,0,sizeof(head));
	counter=0;
	for(int i=1,u,v,w;i<=m;i++){
		cin>>u>>v>>w;
		adde(u,v,w);
		adde(v,u,w);
	}
}

struct node{
	ll cost;
	int bike,u;
	bool operator<(const node &x)const{
		return (cost==x.cost)?bike>x.bike:cost>x.cost;
	}
};
int s[maxn];
ll d[maxn][maxn];


ll dijkstra(){
	memset(d,0x3f,sizeof(d));
	priority_queue<node> h;
	d[1][s[1]]=0;
	h.push(node{1,s[1],1});
	while(!h.empty()){
		int u=h.top().u,bike=h.top().bike;
		h.pop();
		if(u==n)return d[u][bike];
		if(bike>s[u]){
			d[u][s[u]]=min(d[u][s[u]],d[u][bike]);
			bike=s[u];
		}
		for(int i=head[u],v,w;i;i=e[i].nxt){
			v=e[i].v;w=e[i].w;
			if(d[v][bike]>d[u][bike]+1ll*bike*w){
				d[v][bike]=d[u][bike]+1ll*bike*w;
				h.push(node{d[v][bike],bike,v});
			}
		}
	}
	return inf;
}

int main(){
	cin>>T;
	while(T--){
		init();
		for(int i=1;i<=n;i++)
			cin>>s[i];
		
		cout<<dijkstra()<<endl;
	}
	return 0;
} 
相关推荐
Justice Young6 分钟前
算法分析与设计实验:贪心法求解0/1背包问题的局限性
算法
黎阳之光12 分钟前
无感定位·智管全域:黎阳之光人员无感定位管理系统,重新定义安全与效率
人工智能·物联网·算法·安全·数字孪生
小许同学记录成长25 分钟前
网格简化算法 — Edge Collapse(边塌缩)
qt·算法
凯瑟琳.奥古斯特28 分钟前
力扣1001网格照明解法
算法·leetcode·职场和发展
fengenrong31 分钟前
20260601
算法·深度优先·图论
晚笙coding34 分钟前
从“看起来像双指针”到真正的动态规划 —— 最长公共子序列
算法·动态规划
05候补工程师1 小时前
【考研高数核心突破】极限的本质、高频解题套路与海涅定理深度解析(附经典例题思维导图式拆解)
经验分享·笔记·考研·算法
智者知已应修善业1 小时前
【51单片机8个LED的花样12亮34熄56间隔78闪烁3秒3闪烁】2023-11-4
c++·经验分享·笔记·算法·51单片机
老鱼说AI1 小时前
统计学习方法第五章:从浅入深解析决策树
人工智能·深度学习·算法·决策树·机器学习·学习方法
KaMeidebaby1 小时前
卡梅德生物技术快报|蛋白修饰调控 NETosis 分子机制及实验研究进展
前端·数据库·人工智能·算法·百度