二分答案+dijkstra
这道题有被改编的另一道题:“通往奥格瑞玛的道路”,相信你也做过吧。。。
看到“交的费用中最多的一次最少是多少”,就应该想到二分答案了。
所以我们二分费用,判断最多的费用是一个\(mid\)的时候可不可以成功到达终点。
如何判断能否成功到达终点?
不要说用SPFA!因为……被卡了。
我们用不被卡的dijkstra的堆优化就可以了。反正又没有负权边。
震惊!我这道题被卡了一段时间的原因居然是……
二分写挂了!
众所周知,二分答案差不多有两种主流的写法,一种两个变量的,一种三个变量的。
两个变量的可以实现,并且不容易错。在while上面写的条件是l < r
。
三个变量的实现必须是整数,如果是浮点数你就GG了。在while上的条件是l <= r
。我错在了这个地方,就丢了一半的分!
所以好好写二分哦!
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
const int maxn = 10005, maxm = 50005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct Edges
{
ll next, to, weight;
} e[maxm << 1];
ll head[maxn], tot;
ll a[maxn], f[maxn];
ll dist[maxn];
ll n, m, s, t, c;
struct Heapnodes
{
ll d, u;
bool operator < (const Heapnodes &rhs) const
{
return d > rhs.d;
}
};
ll read()
{
ll ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
return s * ans;
}
void link(ll u, ll v, ll w)
{
e[++tot] = (Edges){head[u], v, w};
head[u] = tot;
}
bool check(ll mid)
{
memset(dist, 0x3f, sizeof dist);
std::priority_queue<Heapnodes> heap;
dist[s] = 0; heap.push((Heapnodes){dist[s], s});
while(!heap.empty())
{
Heapnodes x = heap.top(); heap.pop();
int d = x.d, u = x.u;
if(d != dist[u]) continue;
if(f[u] > mid) continue;
for(ll i = head[u]; i; i = e[i].next)
{
ll v = e[i].to;
if(f[v] > mid) continue;
if(dist[u] + e[i].weight < dist[v])
{
dist[v] = dist[u] + e[i].weight;
heap.push((Heapnodes){dist[v], v});
}
}
}
return dist[t] <= c;
}
int main()
{
n = read(), m = read(), s = read(), t = read(), c = read();
for(int i = 1; i <= n; i++)
{
a[i] = f[i] = read();
}
while(m--)
{
ll x = read(), y = read(), z = read();
link(x, y, z); link(y, x, z);
}
if(!check(INF))
{
printf("-1\n");
return 0;
}
std::sort(a + 1, a + n + 1);
ll left = 1, right = n, ans = -1;
while(left <= right)// !!!!
{
ll mid = (left + right) >> 1;
if(check(a[mid])) ans = a[mid], right = mid - 1;
else left = mid + 1;
}
printf("%lld\n", ans);
return 0;
}