在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量
有一天他醒来后发现自己居然到了联盟的主城暴风城
在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛
在艾泽拉斯,有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。
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
10
对于60%的数据,满足n≤200,m≤10000,b≤200
对于100%的数据,满足n≤10000,m≤50000,b≤1000000000
对于100%的数据,满足ci≤1000000000,fi≤1000000000,可能有两条边连接着相同的城市。
题目意思:
要找出满足能走通到终点的最少的钱
(这里的最少钱,即为路过的需要最大钱的点的钱)
即枚举出满足条件的最少钱
ci的范围达到10^9,则需要二分找出满足条件的最少钱
满足条件为:能通过的每个点需要的钱少于输入判断的钱, 且到达终点的最短路小于等于他的血量
//二分+dijkstra 枚举 验证
#include
using namespace std;
const int MAXV = 10005;
const int INF = 1000000005;
struct edge{
int v;
int w;
edge(int _v, int _w): v(_v), w(_w) {}
edge(){}
};
struct node{
int v;
int d;
friend bool operator < (const node &a, const node &b)
{
return a.d > b.d;
}
node(int _v, int _d): v(_v), d(_d) {}
node(){}
};
int d[MAXV];
vector<edge> G[MAXV];
priority_queue<node> pq;
int cost[MAXV];
int vis[MAXV];
int n, m, b;
bool dijkstra(int s)
{
if(cost[1] > s)
return false;
fill(d, d+MAXV, INF);
fill(vis, vis+MAXV, false);
d[1] = 0;
pq.push(node(1,0));
while(!pq.empty())
{
int u = pq.top().v;
pq.pop();
if(vis[u])
continue;
vis[u] = true;
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i].v;
int l = G[u][i].w;
if(d[u]+l < d[v] && cost[v] <= s)
{
d[v] = d[u]+l;
pq.push(node(v, d[v]));
}
}
}
if(d[n] <= b)
return true;
else
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&b);
int most = 0, least = INF;
for(int i = 1; i <= n; i++)
{
scanf("%d",&cost[i]);
most = max(most, cost[i]); //找出二分的最大最小边界
least = min(least, cost[i]);
}
//也可以用一个数组存每个值,然后sort排序之后,只要对数组内的数二分,时间复杂度会更低一些
for(int i = 1; i <= m; i++)
{
int ai, bi, ci;
scanf("%d%d%d",&ai,&bi,&ci);
G[ai].push_back(edge(bi, ci));
G[bi].push_back(edge(ai, ci));
}
if(!dijkstra(INF))
//特判是否联通,不能用least>mid因为可能是相等退出,但未夹出的相等位置
//也可以做标记flag,看是否至少成立一次
{
printf("AFK");
return 0;
}
while(most > least)
{
int mid = most + (0.5*(least-most));
if(dijkstra(mid))
most = mid;
else
least = mid+1;
}
printf("%d",least);
return 0;
}