卧薪尝胆,厚积薄发。
USACO09DEC GOLD 牛收费路径Cow Toll Paths
Date: Thu Oct 18 21:45:21 CST 2018 In Category: NoCategory

Description:

每个点有一个点权,每条边有一个边权,一条路径的长度 $=($ 边权之和 $)+($ 经过的所有点中点权的最大值 $)$ , $q$ 次询问点对之间的最短路。
$1\leqslant n\leqslant 250,1\leqslant q\leqslant 10^4$

Solution:

看算法复杂度应该是 $O(n^3)$ 的,看点对之间复杂度不难想到 $floyed$ ,这个时候需要一些对 $floyed$ 原理的理解。
$floyed$ 的本质是 $f[k][i][j]$ 表示只经过 $[1,k]$ 这些点从 $i$ 到 $j$ 的最短路( $i$ 和 $j$ 不算),那么这道题既然要求最大,就可以先把点排序,依次循环,这样保证更新的路径上的点权都 $\leqslant k$ ,那么如果 $i$ 和 $j$ 的点权都小于 $k$ 的,就可以用 $f[i][j]+c[k]$ 更新答案,最后 $O(1)$ 回答询问。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,m,q;
#define MAXN 251
int f[MAXN][MAXN];
int ans[MAXN][MAXN];
int c[MAXN];
bool cmp(int a,int b){return c[a] < c[b];}
int s[MAXN],p[MAXN];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= n;++i)scanf("%d",&c[i]);
for(int i = 1;i <= n;++i)s[i] = i;
sort(s + 1,s + 1 + n,cmp);
for(int i = 1;i <= n;++i)p[s[i]] = i;
int a,b,v;
memset(f,0x3f,sizeof(f));
for(int i = 1;i <= n;++i)f[i][i] = 0;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&a,&b,&v);
f[b][a] = f[a][b] = min(f[a][b],v);
}
memset(ans,0x3f,sizeof(ans));
for(int k = 1;k <= n;++k)
{
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= n;++j)
{
f[i][j] = min(f[i][j],f[i][s[k]] + f[s[k]][j]);
if(c[i] <= c[s[k]] && c[j] <= c[s[k]])ans[i][j] = min(ans[i][j],f[i][j] + c[s[k]]);
}
}
}
for(int i = 1;i <= q;++i)
{
scanf("%d%d",&a,&b);
printf("%d\n",ans[a][b]);
}
return 0;
}
In tag: 图论-floyed
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡