问题 B: 小说(二分最短路)

题目描述
由于小X是一位奆老,奆老总是忙得一刻也停不下来。他刚刚准备完食物,小X童年的挚友小S和小Z来找他帮忙了……
小S和小Z十分喜欢看网络写手“25”的小说,但由于需要付费才能阅读,而小S和小Z的零花钱有非常少,他们只能找小X靠黑科技侵入给网站,把小说给他们。
然而小X又非常的爱慕虚荣,他要小S和小Z到自己家里来取小说。
小S、小Z和小X都居住在扬中市,扬中市共有n个小区,m条主干道(假设每条主干道都是双行线)。小S家住在1号小区,小X家住在n号小区。小S每经过一条主干道需要耗费z点体力,但由于小S的人脉非常广,每当他到达一个小区,他都会和好友攀谈直到体力回满。
由于小Z也希望能看到小说,所以他答应帮助小S k次,这k次小S经过主干道不需要耗费体力。
由于小S生性懒惰,他希望耗费最少的体力到达小X家,请问他最少耗费多少体力?
注意:如果小S到小X家可以一路上都由小Z背着,那么体力上限为0;
如果小S到不了小X家,小S会很伤心,体力上限为-1;
输入
第1行三个整数n,m,k,意思如题目描述。
第2到第n+1行是x,y,z指走连接x号小区和y号小区的主干道要耗费z点体力
输出
一行一个整数,表示小S最少耗费的体力。

因为z<=1e6,所以二分。l=0,r=1e6,check(mid)代表当体力上限为mid时利用k次免费机会能否到达n点。check函数跑dijkstra,把经过的边如果权值大于mid的权值赋值为1,小于等于的为0,然后得到的最短路如果dis[n]大于k说明k次机会不够然后return false。

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
struct skt{
	int d,x;
	friend bool operator<(skt a,skt b){
		return a.d>b.d;
	}
};
int limit,n,k;
int have[1010],dis[1010];
vector<int>v[1010],w[1010];
void dijkstra(){
	priority_queue<skt>q;
	memset(dis,INF,sizeof(dis));
	memset(have,0,sizeof(have));
	skt b;
	b.x=1;b.d=0;
	q.push(b);
	dis[1]=0;
	while(!q.empty()){
		int i;
		skt now=q.top();
		q.pop();
		if(!have[now.x]){
			have[now.x]=1;
			for(i=0;i<v[now.x].size();i++){
				int cost=w[now.x][i];
				if(cost>limit)
				cost=1;
				else
				cost=0;
				if(dis[now.x]+cost<dis[v[now.x][i]]){
					dis[v[now.x][i]]=dis[now.x]+cost;
					skt p;
					p.x=v[now.x][i];
					p.d=dis[v[now.x][i]];
					q.push(p);
				}
			}
		}
	}
}
bool check(int mid){
	limit=mid;
	dijkstra();
	if(dis[n]>k)
	return false;
	else
	return true;
}
int main(void){
	int m,i,a,b,c;
	scanf("%d%d%d",&n,&m,&k);
	for(i=0;i<m;i++){
		scanf("%d%d%d",&a,&b,&c);
		v[a].push_back(b);
		w[a].push_back(c);
		v[b].push_back(a);
		w[b].push_back(c);
	}
	limit=1e6+100;
	dijkstra();
	if(dis[n]==INF){
		printf("-1\n");
		return 0;
	}
	int l=0,r=1e6,mid;
	int ans=0;
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid)){
			ans=mid;
			r=mid-1;
		}
		else
		l=mid+1;
	}
	cout<<ans<<"\n";
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值