题目描述
由于小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;
}