#(mathcal{color{red}{Description}})
有一个图,求其在(1-N)的最短路小于一个给定值下,点权最大值的最小值。
#(mathcal{color{red}{Solution}})
(emmm)这个题也是几天前做的……正在填坑(qwq)。
这道题虽然在(Luogu)上显示是和(color{cyan}{A Link})一个难度的,但是要明显简单很多好不好……
正解的话,很显然要二分一个血量…… 因为二分(答案)是有套路的:
1、求最……的……(一般不可以静态求)
2、求什么就二分什么
3、 一般是反着推,就是用二分出的结果去推条件是否满足,或者状态是否合法
于是,二分交费,然后在(check)的时候,由于二分的是最大值,所以比二分的(x)大的就不走,小的可以走,以此为限制条件(SPFA),观察跑出来的最短路是否大于拥有的血量,大的话自然就不合法,小的话自然合法。然后就做完了(qwq)
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
#define to(k) e[k].to
using namespace std ;
const int MAXN = 62050 ;
struct edge{
ll to, next, v ;
}e[MAXN << 1] ;
queue<ll> q ;
ll head[MAXN << 1], cnt, dist[MAXN], i, k, ct ;
ll base[MAXN], l, r, mid, a, b, c, N, M, K, vis[MAXN], now ;
inline void init(){
memset(dist, 0x3f, sizeof(dist)), memset(vis, 0, sizeof(vis)) ;
queue<ll> emt ; swap(q, emt), q.push(1), vis[1] = 1, dist[1] = 0 ;
}
inline bool check(ll x){
init() ;
while(!q.empty()){
now = q.front(), q.pop(), vis[now] = 0 ;
for(k = head[now]; k ; k = e[k].next){
if(base[to(k)] > x) continue ;
if(dist[to(k)] > dist[now] + e[k].v){
dist[to(k)] = dist[now] + e[k].v ;
if(!vis[to(k)]){
vis[to(k)] = 1 ;
q.push(to(k)) ;
}
}
}
}
if(dist[N] > K) return 0 ; return 1 ;
}
inline void add(int u, int v, int w){
e[++cnt].to = v, e[cnt].v = w ;
e[cnt].next = head[u], head[u] = cnt ;
}
int main(){
cin >> N >> M >> K ;
for(i = 1; i <= N; i ++) cin >> base[i] ;
for(i = 1; i <= M; i ++){
cin >> a >> b >> c ;
add(a, b, c), add(b, a, c) ;
}l = 0, r = 1000000000 ;
while(l < r){
mid = (l + r) >> 1 ;
if(check(mid)) r = mid ;
else l = mid + 1 ;
}
if(l == 1000000000) cout << "AFK" ;
else cout << l ;
}
幕后花絮:这个题我特别细心地判了(-1),结果让输出(AFK)……好吧人生就是这样的跌宕起伏(ORZ)……然后现在的我看二分答案就像我当年的我看快速幂一样,绝对不是不会,可以充分体现出我的“OI”思维没有多高……因为常人自然难以理解,(Coder)素质越高,理解起来越简单……现在的状态嘛…大概写出一份二分答案来问题不是很大,但是要做到稔熟于心,也还需要一段路要走啊(qwq)。