【洛谷】【二分答案+最短路】P1462 通往奥格瑞玛的道路
【題目描述:】
在艾澤拉斯,有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 輸出樣例#1: 10 輸入輸出樣例?
【算法分析:】
問題可以看作:
給定一張圖,給定邊權和點權,給定一個最大邊權,
問,從點1到點n的路徑的總長度不大于最大邊權時點權的最大值最小
假設一個最大值,問題就變成了
求出一條經過的點的點權都不大于這個最大值的最短路徑,并且這條最短路的長度小于最大邊權(生命值為0就GG了)
?
好像可以二分答案,證一證它的單調性:
當一個數num被選為最大值的時候,如果存在一條“經過的點的點權都不大于這個最大值的最短路徑,并且這條最短路的長度小于最大邊權”
則num可以選為最大值。
當num變小時,可以經過的城市變少,可選的點數變少,受到的傷害便可能增多,
使受到的傷害盡可能大(但不能超過總生命值),最大的點權值就會盡可能小,
故num不一定是最優解,所以從[l, mid]內尋找解
當num作為最大值過小時,就要從[mid + 1, r]中尋找解.
?
也就是說這道題將傷害視作邊權,二分點權最大值,跑最短路松弛的條件多加了一個:松弛的點的點權必須小于最大點權
每次跑完最短路后如果受到的傷害小于血量那么這個最大點權便是一個解.
?
【代碼:】
1 //通往奧格瑞瑪的道路 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 7 const int MAXN = 10000 + 1; 8 const int MAXM = 50000 + 1; 9 const int INF = 0x3f3f3f3f; 10 11 int n, m, blood; 12 int city[MAXN]; 13 14 int edge_num, head[MAXN]; 15 struct edge { 16 int len, to, next; 17 }h[MAXM * 2]; 18 19 inline void Add(int from, int to, int len) { 20 h[++edge_num].next = head[from]; 21 h[edge_num].to = to, h[edge_num].len = len; 22 head[from] = edge_num; 23 } 24 25 inline int read() { 26 int x = 0; char ch = getchar(); 27 while(ch < '0' || ch > '9') ch = getchar(); 28 while(ch >= '0' && ch <= '9') 29 x = (x << 3) + (x << 1) + ch - 48, ch = getchar(); 30 return x; 31 } 32 33 int fro, rear; 34 int dis[MAXN], que[MAXN * 20]; 35 bool in_que[MAXN]; 36 void SPFA(int money) { 37 for(int i = 0; i <= n; i++) dis[i] = INF; 38 memset(in_que, 0, sizeof(in_que)); 39 in_que[1] = 1, dis[1] = 0; 40 que[fro = rear = 1] = 1; 41 while(fro <= rear) { 42 int x = que[fro++]; 43 in_que[x] = 0; 44 for(int i = head[x]; i; i = h[i].next) { 45 int l = h[i].len, y = h[i].to; 46 if(dis[x] + l < dis[y] && city[y] <= money) { 47 dis[y] = dis[x] + l; 48 if(!in_que[y]) in_que[y] = 1, que[++rear] =y; 49 } 50 } 51 } 52 } 53 54 inline bool check(int money) { 55 SPFA(money); 56 return dis[n] < blood; 57 } 58 int main() { 59 int l = 0, r = 0; 60 n = read(), m = read(), blood = read(); 61 for(int i = 1; i <= n; ++i) { 62 city[i] = read(); 63 r = max(r, city[i]); 64 } 65 l = max(city[1], city[n]); 66 for(int i = 1; i <= m; ++i) { 67 int a, b, c; 68 a = read(), b = read(), c = read(); 69 if(a != b) { 70 Add(a, b, c); 71 Add(b, a, c); 72 } 73 } 74 if(!check(r)) { puts("AFK"); return 0; } 75 while(l <= r) { 76 int mid = (l + r) >> 1; 77 if(!check(mid)) l = mid + 1; 78 else r = mid - 1; 79 } 80 printf("%d\n", l); 81 }?
轉載于:https://www.cnblogs.com/devilk-sjj/p/9042030.html
總結
以上是生活随笔為你收集整理的【洛谷】【二分答案+最短路】P1462 通往奥格瑞玛的道路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java.lang.IllegalSta
- 下一篇: STS插件_ springsource-