洛谷 P1462 通往奥格瑞玛的道路 解题报告
P1462 通往奥格瑞玛的道路
题目背景
在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量
有一天他醒来后发现自己居然到了联盟的主城暴风城
在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛
题目描述
在艾泽拉斯,有\(n\)个城市。编号为\(1,2,3,...,n\)。
城市之间有\(m\)条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设\(1\)为暴风城,\(n\)为奥格瑞玛,而他的血量最多为\(b\),出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入输出格式
输入格式:
第一行3个正整数,\(n\),\(m\),\(b\)。分别表示有\(n\)个城市,\(m\)条公路,歪嘴哦的血量为\(b\)。
接下来有\(n\)行,每行\(1\)个正整数,\(f_i\)。表示经过城市\(i\),需要交费\(f_i\)元。
再接下来有\(m\)行,每行3个正整数,\(a_i\),\(b_i\),\(c_i\) \((1<=a_i,b_i<=n)\)。表示城市\(a_i\)和城市\(b_i\)之间有一条公路,如果从城市\(a_i\)到城市\(b_i\),或者从城市\(b_i\)到城市\(a_i\),会损失\(c_i\)的血量。
输出格式:
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出\(AFK\)。
说明
对于60%的数据,满足\(n≤200,m≤10000,b≤200\)
对于100%的数据,满足\(n≤10000,m≤50000,b≤1000000000\)
对于100%的数据,满足\(c_i≤1000000000\),\(f_i≤1000000000\),可能有两条边连接着相同的城市。
首先读懂题:他所经过的所有城市中 最多的一次收取的费用 的最小值是多少。
意思就是他可能选择的某条路上有一个点,要交的保护费是所有中最多的。
他要选一条路,让这个最多的保护费最小。
很明显的二分答案的特征吧?
每次比\(mid\)(二分的保护费)大的边删掉
而损失血量其实就是边权,跑最短路即可
不过题目有点没说清楚,如果刚好没血了到的是不算数的,有点坑。
另外有一点,最好开\(long\) \(long\),不开的话,要控制不爆可能有点点难搞(\(0x3f\)比十亿稍稍大一点)
说一下自己智障的错误吧。。
- 前向星开边只开了\(50000\)个点,刚从\(vector\)转过来没有意识到双向边要开两倍。
- 忘记输出\(AFK\)了(这样的错误也能犯啊...)
- 二分时先把保护费排了个序离散,然后,然后我们就没管它了啊!!!(哭...呜呜呜)
code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
const int N=10002;
const int M=100002;
ll max(ll x,ll y) {return x>y?x:y;}
ll min(ll x,ll y) {return x<y?x:y;}
struct Edge
{
ll to,next,w;
}edge[M];
ll head[N],cnt=0;
ll n,m,b,f[N],f0[N];
void add(ll u,ll v,ll w)
{
edge[++cnt].next=head[u];
edge[cnt].to=v;
edge[cnt].w=w;
head[u]=cnt;
}
ll read()
{
ll x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x;
}
queue <int > q;
ll vis[N],dis[N];
bool check(ll c)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
vis[1]=1,dis[1]=0;
q.push(1);
while(!q.empty())
{
int u=q.front();
vis[u]=0;
q.pop();
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to,w=edge[i].w;
if(dis[v]>dis[u]+w&&f[v]<=c)
{
dis[v]=dis[u]+w;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
if(b<=dis[n]) return false;
return true;
}
int main()
{
n=read(),m=read(),b=read();
for(int i=1;i<=n;i++) f[i]=read(),f0[i]=f[i];
sort(f0+1,f0+1+n);
ll u,v,w;
for(int i=1;i<=m;i++)
{
u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
}
ll l=1,r=n;
if(!check(f0[r])) {printf("AFK\n");return 0;}
while(l<r)
{
int mid=l+r>>1;
if(check(f0[mid]))
r=mid;
else
l=mid+1;
}
printf("%lld\n",f0[l]);
return 0;
}
2018.5.13