洛谷P1462 通往奥格瑞玛的道路
题目背景
在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量
有一天他醒来后发现自己居然到了联盟的主城暴风城
在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛
题目描述
在艾泽拉斯,有\(n\)个城市。编号为\(1,2,3,...,n\)。
城市之间有\(m\)条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,\(n\)为奥格瑞玛,而他的血量最多为\(b\),出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入输出格式
输入格式:
第一行3
个正整数,\(n\),\(m\),\(b\)。分别表示有\(n\)个城市,\(m\)条公路,歪嘴哦的血量为\(b\)。
接下来有\(n\)行,每行1
个正整数,\(f_i\)。表示经过城市\(i\),需要交费\(f_i\)元。
再接下来有\(m\)行,每行3
个正整数,\(a_i\),\(b_i\),\(c_i\)\((1 \leq a_i,b_i \leq n)\)。表示城市\(a_i\)和城市\(b_i\)之间有一条公路,如果从城市\(a_i\)到城市\(b_i\),或者从城市\(b_i\)到城市\(a_i\),会损失\(c_i\)的血量。
输出格式:
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出AFK
。
思路
二分答案
二分交费的最小值\(k\)
然后判断是否可行的方法是:在图中删去所有费用大于\(k\)的点,再跑最短路,如果最短路的值大于歪嘴哦的血量,那就不可行,否则可行
CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define MAXN 10010
#define MAXM 200010
struct Node{
int u,v,w;
Node(){}
Node(int u,int v,int w):u(u),v(v),w(w){}
}p[MAXM];
struct R{
int id,dis;
R(){}
R(int id,int dis):id(id),dis(dis){}
bool operator < (const R &a) const{
return dis>a.dis;
}
}tmp;
int head[MAXN],Next[MAXM],dis[MAXN],cost[MAXN];
priority_queue<R> mque;
bool vis[MAXN];
int i,j,k,m,n,u,v,w,tot,l,r,mid,ans,b,upborder;
bool flag;
void addNode(int u,int v,int w){
p[++tot]=Node(u,v,w);
Next[tot]=head[u],head[u]=tot;
p[++tot]=Node(v,u,w);
Next[tot]=head[v],head[v]=tot;
}
bool dijkstra(int src,int goal){
if(cost[src]>mid) return false;
while(!mque.empty()) mque.pop();
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[src]=0;
mque.push(R(src,0));
while(!mque.empty()){
tmp=mque.top(); mque.pop();
if(vis[tmp.id]) continue;
vis[tmp.id]=true;
for(register int i=head[tmp.id];i+1;i=Next[i]){
if(cost[p[i].v]<=mid&&dis[p[i].u]+p[i].w<dis[p[i].v]){
dis[p[i].v]=dis[p[i].u]+p[i].w;
mque.push(R(p[i].v,dis[p[i].v]));
}
}
}
if(dis[goal]<b) return true;
return false;
}
void solve(){
l=0,r=1000000000;
flag=false;
while(l<r){
mid=(l+r)>>1;
if(dijkstra(1,n)){
r=mid;
flag=true;
}else{
l=mid+1;
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&b);
memset(head,-1,sizeof(head));
tot=-1; upborder=0;
for(i=1;i<=n;i++){
scanf("%d",cost+i);
}
for(i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
addNode(u,v,w);
upborder=max(upborder,w);
}
solve();
if(flag){
printf("%d\n",l);
}else{
printf("AFK\n");
}
return 0;
}