【洛谷P1462】【二分+堆优化dij】

时间:2023-03-09 08:46:13
【洛谷P1462】【二分+堆优化dij】

题目描述

在艾泽拉斯,有n个城市。编号为1,2,3,...,n。

城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。

每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。

假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。

歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。

题目分析

题目说了那么多,其实就是让求在角色不死亡的情况下移动过程遇到的F[i]的最大值的最小值..【看到最大值的最小值就应该立马想到二分啊..然而蒟蒻终究是蒟蒻..没想到二分..而是无脑堆优化的使用dij..结果TLE到怀疑人生,看到别人的题解之后才想到用二分..orz..】

题意这样就很明白了 二分是一定要用的 这种问法基本十个有九个是要用二分

那么我们要二分什么呢 血量还是金钱呢

因为要求的是收费所以就二分金钱好了////

二分的条件就是 以当前值为最大值 ,不走大于二分值的点,然后用堆优化的dij判断是否连通就行了

 #include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn1=;
const int maxn2=;
const int maxn3=;
struct pot{
int id;
int rest;
bool operator <(const struct pot&AA)const{
return rest < AA.rest;
}
};
struct edge{
int next;
int to;
int len;
}EDGE[maxn2*+];
int dist[maxn1+],head[maxn1+],dist1[maxn1+];
int n,m,b;
int edge_cnt=;
priority_queue<struct pot>pq;
void add(int x,int y,int z)
{
EDGE[edge_cnt].to=y;
EDGE[edge_cnt].next=head[x];
EDGE[edge_cnt].len=z;
head[x]=edge_cnt++;
}
int mmin=-;
bool dij(int x)
{
memset(dist1,,sizeof(dist1));
while(!pq.empty())
{
pq.pop();
}
pq.push((struct pot){,b});
while(!pq.empty())
{
struct pot aa=pq.top();pq.pop();
if(aa.rest<dist1[aa.id])continue;
for(int i = head[aa.id]; i != - ; i=EDGE[i].next)
{
int v=EDGE[i].to;
if(dist[v]<=x&&aa.rest-EDGE[i].len>)
{
if(v==n){
return true;
}
if(dist1[v]<aa.rest-EDGE[i].len)
{
dist1[v]=aa.rest-EDGE[i].len;
pq.push((struct pot){v,aa.rest-EDGE[i].len});
}
}
}
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&b);
int r=;
for(int i = ; i <= n ; i++)
{
scanf("%d",&dist[i]);
r=max(r,dist[i]);
}
memset(head,-,sizeof(head));
while(m--)
{
int q,w,e;
scanf("%d%d%d",&q,&w,&e);
add(q,w,e);
add(w,q,e);
}
int l=max(dist[],dist[n]);
bool flag=false;
while(l<=r)
{
int mid=(l+r)/;
if(dij(mid)){
r=mid-;
flag=true;
}
else
{
l=mid+;
}
}
if(!flag)
printf("AFK\n");
else
cout << l<< endl;
return ;
}

【洛谷P1462】【二分+堆优化dij】