通往奥格瑞玛的道路
题目描述
在艾泽拉斯,有n个城市。编号为1,2,3,...,n。
城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入格式:
在艾泽拉斯,有n个城市。编号为1,2,3,...,n。
城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入格式:
第一行3个正整数,n,m,b。分别表示有n个城市,m条公路,歪嘴哦的血量为b。
接下来有n行,每行1个正整数,fi。表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,会损失ci的血量。
输出格式:
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出AFK。
输入样例#1:
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
接下来有n行,每行1个正整数,fi。表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,会损失ci的血量。
输出格式:
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出AFK。
输入样例#1:
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
输出样例#1:
10
说明:
对于60%的数据,满足n≤200,m≤10000,b≤200
对于100%的数据,满足n≤10000,m≤50000,b≤1000000000
对于100%的数据,满足ci≤1000000000,fi≤1000000000,可能有两条边连接着相同的城市。
解析:
最短路+二分。
由于题目要求求出最大点权的最小值,我们就可以二分最大点权,用dijkstra进行验证。
注意:二分的low=min(f[i]),high=max(g[i]);
代码:
#include <bits/stdc++.h>
using namespace std;
const int Max=100100;
long long n,m,sum,s;
long long l,r,mid;
long long num[Max];
long long dis[Max],first[Max],f[Max];
struct shu{int to,next,len;};
shu bian[Max];
inline void build(int x,int y,int z) /建边
{
s++;
bian[s].next=first[x];
first[x]=s;
bian[s].to=y;
bian[s].len=z;
}
inline int check(int num) //dijkstra验证
{
priority_queue<pair<int,int> >q;
memset(dis,127,sizeof(dis));
long long y=dis[n];
dis[1]=0;
q.push(make_pair(0,1));
while(!q.empty())
{
int point=q.top().second;
q.pop();
for(int u=first[point];u;u=bian[u].next)
{
if(dis[point]+bian[u].len<dis[bian[u].to]&&f[bian[u].to]<=num)
{
dis[bian[u].to]=dis[point]+bian[u].len;
q.push(make_pair(-dis[bian[u].to],bian[u].to));
}
}
}
if(dis[n]>=y||sum-dis[n]<=0) return 0; //如果不能达到或者血量不够,则不满足条件
else return 1;
}
int main()
{
// freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
scanf("%d%d%d",&n,&m,&sum);
for(int i=1;i<=n;i++) {scanf("%d",&f[i]);num[i]=f[i];}
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
build(x,y,z);
build(y,x,z);
}
sort(num+1,num+n+1);
l=1;
r=n;
int flag=0;
while(l<=r) //二分
{
mid=(l+r)/2;
if(check(num[mid])&&num[mid]>=f[1]) {r=mid-1;flag=1;}
else l=mid+1;
}
if(flag==1) cout<<num[r+1]<<endl;
else cout<<"AFK"<<endl;
return 0;
}