P2966 [USACO09DEC]Cow Toll Paths G
Posted lpf-666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2966 [USACO09DEC]Cow Toll Paths G相关的知识,希望对你有一定的参考价值。
题意描述
这道题翻译的是真的不错,特别是第一句话
给定一张有 (n) 个点 (m) 条边的无向图,每条边有边权,每个点有点权。
两点之间的路径长度为所有边权 + 点权的最大值,求 (q) 组 (s o t) 的最短路径。
算法分析
数据范围 (nleq 250)(和谐数字)Floyd 乱搞没跑了。
但是这道题唯一与普通全源最短路的不同之处在于,这道题要求一个最大点权。
一开始我的想法是二分找最小点权,就是每次只走点权 < mid 的点跑 dijkscal。
但是复杂度好像并不是很低(能过?),所以要有一个更强的优化。(而且不是说好了用 Floyd 吗)
首先,你学习 Floyd 如果仅仅停留在背那 5 行代码的话就太可悲了,Floyd 最重要的是它的原理呀。
为什么最外层循环是 k?因为 k 是中间节点,所以这里有一个性质:
当 Floyd 算法遍历到 (k) 时,当前的 (dis(i,j)) 除去 (i,j) 两个端点外,中途经过的点都 (<k)。
那么利用这个性质我们可以有一个很高效的算法((O(n^3)) 叫高效):
- 对于每个点按照点权从小到大来排序。
- Floyd 时,最大点权一定是 ((i,j,k)) 三点中的一个。
然后每次仅边权和答案两个数组分开计算即可。
代码实现
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 300
using namespace std;
int n,m,q,d[N][N],dis[N][N],rank[N];
struct node{
int nu,id;
}a[N];
int read(){
int x=0,f=1;char c=getchar();
while(c<‘0‘ || c>‘9‘) f=(c==‘-‘)?-1:1,c=getchar();
while(c>=‘0‘ && c<=‘9‘) x=x*10+c-48,c=getchar();
return x*f;
}
bool cmp(node a,node b){return a.nu==b.nu?a.id<b.id:a.nu<b.nu;}
int main(){
memset(d,0x3f,sizeof(d));
memset(dis,0x3f,sizeof(dis));
n=read(),m=read(),q=read();
for(int i=1;i<=n;i++)
a[i].nu=read(),a[i].id=i,d[i][i]=0;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
rank[a[i].id]=i;
int u,v,w;
for(int i=1;i<=m;i++)
u=read(),v=read(),w=read(),d[rank[u]][rank[v]]=d[rank[v]][rank[u]]=min(d[rank[u]][rank[v]],w);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(i==j) continue;
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
dis[i][j]=min(dis[i][j],d[i][j]+max(a[k].nu,max(a[i].nu,a[j].nu)));
}
for(int i=1;i<=q;i++)
u=read(),v=read(),printf("%d
",dis[rank[u]][rank[v]]);
return 0;
}
完结撒花
以上是关于P2966 [USACO09DEC]Cow Toll Paths G的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 P2966 [USACO09DEC]牛收费路径Cow Toll Paths
P2966 [USACO09DEC]Cow Toll Paths G
洛谷 2966 [USACO09DEC]牛收费路径Cow Toll Paths
[USACO09DEC]牛收费路径Cow Toll Paths