【2020.8.23NOIP模拟赛】最优路线【Floyed+DP】

题目描述
一个 n n n 个点 m m m 条边的无重边无自环的无向图,点有点权,边有边权,定义一条路径的权值为路径经过的点权的最大值乘边权最大值。求任意两点间的权值最小的路径的权值。


输入格式
第一行两个整数 n,m,分别表示无向图的点数和边数。

第二行 n 个正整数,第 i 个正整数表示点 i 的点权。

接下来 m 行每行三个正整数 u i , v i , w i u_i,v_i,w_i ui,vi,wi,分别描述一条边的两个端点和边权。

输出格式
n 行每行 n 个整数,第 i 行第 j 个整数表示从 i i i j j j 的路径的最小权值,如果从 i 不能到达 j,则该值为 − 1 −1 1。特别地,当 = j =j =j时输出 0 0 0


输入输出样例

输入 #1复制
3 3
2 3 3
1 2 2
2 3 3
1 3 1
输出 #1复制
0 6 3
6 0 6
3 6 0


说明/提示
对于 20 20 20% 的数据, n ≤ 5 , m ≤ 8 n≤5,m≤8 n5,m8

对于 50 50 50% 的数据, n ≤ 50 n≤50 n50

对于 100 100 100% 的数据, n ≤ 500 , m ≤ n ( n − 1 ) / 2 n≤500,m≤n(n−1)/2 n500,mn(n1)/2,边权和点权不超过 1 0 9 10^9 109


解题思路
这道题是 弗洛伊德算法 的改装版。。。

我们定义一个叫做 d i s [ ] [ ] dis[][] dis[][]数组的东西作为我们的转移变量,存储的是从i号点到j号点的最小的最大路径长度乘上路径上的最大点权.

我们先对点权进行从小到大的排序,那么我们就可以保证我们每一次加进去的点(作为我们 F l o y d Floyd Floyd算法的中转点,都是最优秀的,当然我们对于该条路径上的最大值一定还是要和该路径上两边的点的点权进行比较)。。。


代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#pragma GCC optimize(2)
using namespace std;
int n,m;
long long w,x,y,b[510][510],c[510],d[510][510];//b[][]就是两点间的权值最小的路径的权值,额,通俗讲就是我们在求的东东;  c[]是每个点的点权。 ; d[][]是两点间最优路径经过的边权最大值
int read()
{
     
	register int X=0;register bool flag=1; register char ch=getchar();
	while(ch<'0'||ch>'9') {
     if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {
     X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}
struct cc{
     
	int x,y;
}a[100010];
bool cmp(const cc&l,const cc&r)
{
     return l.x<r.x;}
int main(){
     
	n=read();
	m=read();
	memset(d,127,sizeof(d));
	memset(b,127,sizeof(b));
	for(register int i=1;i<=n;i++)
	{
     
		c[i]=read();
		b[i][i]=0;
		a[i].x=c[i];
		a[i].y=i; 
	}
	for(register int i=1;i<=m;i++)
	{
     
		x=read();
		y=read();
		w=read();
		d[x][y]=d[y][x]=w;
		b[x][y]=b[y][x]=min(b[x][y],d[x][y]*max(c[x],c[y]));
	}
	sort(a+1,a+n+1,cmp);//对点权进行从小到大的排序
	for(register int k=1;k<=n;k++)//Floyed ,k枚举中间点(register玄学卡常)
	{
     
		long long bsy=a[k].y;
		for(register int i=1;i<=n;i++)
		{
     
			for(register int j=1;j<=n;j++)
			{
     
			//	if((i!=j)&&(j!=bsy)&&(bsy!=i))
			//	{
     
					if(d[i][j]>max(d[i][bsy],d[bsy][j]))//如果当前这条路径经过的边权最大值更小,也就是这条路更优,就更新。。
					{
     
						d[i][j]=max(d[i][bsy],d[bsy][j]);
						b[i][j]=min(b[i][j],d[i][j]*max(c[bsy],max(c[i],c[j])));
					} 
			//	}
			}
		}
	}
	for(register int i=1;i<=n;i++)
	{
     
		for(register int j=1;j<=n;j++)
		{
     
			if(i==j) printf("0 ");	
			else if(d[i][j]==0) printf("-1 ");
			else printf("%lld ",b[i][j]);
		}
		printf("\n");
	}
}



你可能感兴趣的:(图论,DP,洛古)