通往奧格瑞瑪的道路 題解

通往奧格瑞瑪的道路

洛谷P1462 通往奧格瑞瑪的道路html

題目簡述

本題的描述仍是很清晰的,徹底能夠直接傳送門去看node

可是惟一想要強調的是:初看本題可能會像我同樣認爲是點權+邊權處理而後直接跑最短路...然鵝並非這樣c++


思路分析

我覺得的點權實際上是通過該城市的費用,是最終的答案算法

我覺得的邊權實際上是通過該條邊的流血量,是用來判斷某一條從\(1\)\(N\)的路徑是否合法數組

什麼意思?函數

就是要求咱們找到一條路,知足:spa

  1. 這條路上全部的流血量之和必須<\(b\)(給定的初始血量).net

  2. 這條路上通過的全部城市中最大費用值最小code

又是至關於同時維護兩個東西,難搞htm

以前有些題 中,咱們會選擇「枚舉其中一個再求解另一個的思路

  • 那這道題是否也能這樣作呢?

答案是確定的,可是面對這道題的數據範圍:\(ci≤1000000000,fi≤1000000000\)

  • 單純的枚舉確定是會被T飛的,那咱們不妨再深刻思考一下:有什麼算法或作法可以高效的代替窮舉

對了,那就是二分答案

咱們二分最大費用值最小,而後去\(check\)一下當前二分的答案是否合法:便是否有路徑可以從\(1\)\(N\)且路徑上城市花費值≤當前的答案

  • 那麼問題來了,咱們知道二分的前提條件即二分的數列必須是有序的,可是本題的數據並無保證有序,怎麼辦?

咱們能夠開另一個數組\(C'\)代替原來的城市費用數組\(C\)啊!而後直接對\(C'\)進行\(sort\),那咱們就能夠對\(C'\)這個有序數列進行二分了!

  • 固然,對於輸出「AFK」的狀況,咱們能夠在輸入完後就跑一遍最短路,若是沒法到達或路徑不合法(流血總和≥\(b\))則直接「AFK」走人

代碼Code

  • 先上二分程序段:
sort(cc+1,cc+1+n);  //變成有序序列
ans=cc[n];
l=1;r=n;
while(l<=r) {  //注意一下這裏二分的是下標並非直接的值
     long long mid=(l+r)>>1;
     if(check(cc[mid])==true) {
        ans=cc[mid];
        r=mid-1;
     } 
     else l=mid+1;
}
printf("%lld",ans);
  • 再上\(check\)函數段:
inline bool check(long long x) {
    for(register int i=1;i<=n;i++) flag[i]=0;  //記得清空!
    for(register int i=1;i<=n;i++) {
        if(c[i]>x)   flag[i]=1;  //全部大於當前答案的城市都不能走
    }
    dijkstra();
    if(dis[n]==1000000000+1||dis[n]>=b) return false;
    return true;
}
  • 最後上完整AC程序:
#include <bits/stdc++.h>
using namespace std;
long long b,w,r,ans,l,c[5100005],cc[5100005];
int n,m,u,v,tot,dis[5100005],vis[5100005],flag[5100005];
int head[5100005];
priority_queue<pair<int,int> > shan;

struct node {
	int to,net;
	long long val;
} e[5100005];

inline void add(int u,int v,int w) {
	e[++tot].to=v;
	e[tot].val=w;
	e[tot].net=head[u];
	head[u]=tot;
}

inline void dijkstra() {
	for(register int i=1;i<=n;i++) {
		vis[i]=0;
		dis[i]=1000000000+1;
	}
	dis[1]=0;
	shan.push(make_pair(0,1));
	while(!shan.empty()) {
		int x=shan.top().second;
		shan.pop();
		if(vis[x]) continue;
		vis[x]=1;
		for(register int i=head[x];i;i=e[i].net) {
			int v=e[i].to;
			if(dis[v]>dis[x]+e[i].val&&flag[x]==0&&flag[v]==0) {
				dis[v]=dis[x]+e[i].val;
				shan.push(make_pair(-dis[v],v));
			}
		}
	}
}

inline bool check(long long x) {
	for(register int i=1;i<=n;i++) flag[i]=0;
	for(register int i=1;i<=n;i++) {
		if(c[i]>x)	flag[i]=1;
	}
	dijkstra();
	if(dis[n]==1000000000+1||dis[n]>=b) return false;
	return true;
}

int main() {
	scanf("%d%d%lld",&n,&m,&b);
	for(register int i=1;i<=n;i++) {
		scanf("%lld",&c[i]);
		cc[i]=c[i];
	}
	for(register int i=1;i<=m;i++) {
		scanf("%d%d%lld",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	dijkstra();
	if(dis[n]==1000000000+1||dis[n]>=b) {
		puts("AFK");
		return 0;
	}
	sort(cc+1,cc+1+n);
	ans=cc[n];
	l=1;r=n;
	while(l<=r) {
		long long mid=(l+r)>>1;
		if(check(cc[mid])==true) {
			ans=cc[mid];
			r=mid-1;
		}
		else l=mid+1;
	}
	printf("%lld",ans);
	return 0;
}
相關文章
相關標籤/搜索