AtCoder Beginner Contest 204-E

E-Rush Hour 2
题目大意是:有n个城市,从城市a到城市b会花费c + d /( t +1 )的时间,且0点的时候不允许通行,问能不能从城市1到城市n,能就输出花费的最小时间,不能输出 -1

这个题写的时候很容易想到优先队列的迪杰斯特拉,但是对这个图的存储需要花费一点小心思,需要保留一个最适合出发的时间,这个时间可以从给的公式t + = c + d /( t +1得到,根据高中的知识(a + b > =2 * sqrt( a * b)),可以得知,当t = sqrt (d)-1 时,是最适合出发的时间 ,根据这个最适合的时间来判断并更新时间的位置,小于最适合的时间,就等到最适合的时间,大于就直接走

迪杰斯特拉用到了链式前向星,不会的可以看看我这篇博客

链式前向星

贴上代码

#include<stdio.h>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<math.h>
#include<string.h>
#define ll long long
using namespace std;
typedef pair<ll,ll> pii;
const ll MAX=0x3f3f3f3f3f3f3f3f;
const ll N=1e5+10;
const ll M=2*N;
ll n,m,a,b,c2,d2,tt=MAX,gen1;
ll head[N]={0},to[M],c[M],d[M],dist[M],next1[M],vis[M]={0},cnt;
void add(ll a,ll b,ll c1,ll d1){
	to[++cnt]=b;
	c[cnt]=c1,d[cnt]=d1;
	next1[cnt]=head[a];  //next找的是下一条可以走的路(前面已经联通过的路),线性排序每一条路 
	head[a]=cnt;//head[a]是此时的路 
}
void djs(){
	memset(dist,MAX,sizeof(dist));
	dist[1]=0;
	priority_queue<pii,vector<pii>,greater<pii> > q;
	q.push({0,1});//first 是时间 ,second 是城市i 
	while(q.size()){
		pii p=q.top();
		q.pop();
		if(vis[p.second]){
			continue;
		}
		vis[p.second]=1;
		for(ll i=head[p.second];i;i=next1[i]){   //i是此时是第几条路
		    ll best=MAX;
			ll j=to[i];
			ll x=(ll)sqrt(1.0*d[i]);
			ll L=max(dist[p.second],x-10),R=x+10;
			R=max(R,L);//保证l是个大于0的正数 
			for(ll t=L;t<=R;t++){
				ll s=t+c[i]+d[i]/(t+1);
				best=min(best,s);
			}
			if(dist[j]>best){
				dist[j]=best;
				q.push({best,j});
			}
		}
	}
	if(dist[n]==MAX){
		printf("-1\n");
	}else cout<<dist[n]<<endl;
}
int main(){
	cin>>n>>m;
	for(ll i=0;i<m;i++){
		cin>>a>>b>>c2>>d2;
		add(a,b,c2,d2);
		add(b,a,c2,d2);
	}
	djs();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值