LUOGU P2966 [USACO09DEC]牛收费路径Cow Toll Paths
解题思路
\(floyd\)的变形版,首先要求的是经过的点中所有点最大的,那么我们就按照点权来排序。这样的话每次我们枚举的中转点\(k\)是单调递增的,所以每次的最大值一定是\(i,j,k\)其中一个。最好记两个数组,一个带点权一个不带点权,这样比较好写。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXN = 255;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
int n,m,q,f[MAXN][MAXN],a[MAXN],g[MAXN][MAXN];
struct Data{
int w,id;
}data[MAXN];
inline bool cmp(Data A,Data B){
return A.w<B.w;
}
int main(){
memset(f,0x3f,sizeof(f));
memset(g,0x3f,sizeof(g));
n=rd();m=rd();q=rd();int x,y,z;
for(int i=1;i<=n;i++) data[i].w=rd(),data[i].id=i,f[i][i]=0;
sort(data+1,data+1+n,cmp);
for(int i=1;i<=n;i++) a[data[i].id]=i;
for(int i=1;i<=m;i++){
x=rd(),y=rd(),z=rd();
f[a[x]][a[y]]=f[a[y]][a[x]]=min(f[a[x]][a[y]],z);
}
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;
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
g[i][j]=min(g[i][j],f[i][j]+max(data[k].w,max(data[i].w,data[j].w)));
}
// for(int i=1;i<=n;i++)
// for(int j=1;j<=n;j++) cout<<a[i]<<" "<<a[j]<<" "<<g[a[i]][a[j]]<<endl;
while(q--){
x=rd(),y=rd();
printf("%d\n",g[a[x]][a[y]]);
}
return 0;
}