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
",g[a[x]][a[y]]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9791695.html