最优路线【Floyed】

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


>Input
第一行两个整数 n,m,分别表示无向图的点数和边数。
第二行 n 个正整数,第 i 个正整数表示点 i 的点权。
接下来 m 行每行三个正整数 ui,vi,wi​,分别描述一条边的两个端点和边权。

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


>Sample Input
3 3
2 3 3
1 2 2
2 3 3
1 3 1

>Sample Output
0 6 3
6 0 6
3 6 0

对于 20% 的数据,n≤5,m≤8。
对于 50% 的数据,n≤50。
对于 100% 的数据,n≤500,m≤n(n−1)/2,边权和点权不超过 10^9。


>解题思路
看到这个输出和数据范围,我们很容易想到floyed,但重要的是floyed怎么打 比赛时打的floyed爆0了

floyed一般处理的是边权,但是这道题处理的又有点权又有边权又求的是最大值就很难处理
边权我们可以常规处理,这样我们只要考虑点权
我们对点权进行从小到大排序,floyed的中转点从小到大枚举,这样对于(i,j)中的最大点权,就转化成了 m a x ( a i , a t , a j ) max(ai,at,aj) max(ai,at,aj)这三个点了(如果你质疑ai~at之间有更大的点,那这是8可能的,因为这样我们需要在之前用那个点作为中转点求出(i,t),但是我们的中转点从小到大枚举,这样的情况不可能)。

最后加上疯狂卡常


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 505
#define ll long long
#define rg register
using namespace std;

struct point
{
	ll c;
	int h;
} s[N];
int n, m;
ll a[N], w[N][N], f[N][N];

bool cmp (point aa, point bb) {return aa.c < bb.c;}
ll read ()
{
	ll l = 0;
	char c = getchar();
	while (c > '9' || c < '0') c = getchar();
	while (c >= '0' && c <= '9')
	{
		l = l * 10 + c - '0';
		c = getchar();
	}
	return l;
}
void write (ll l)
{
	if (l > 9) write (l / 10);
	putchar (l % 10 + '0');
}

signed main()
{
	memset (w, 0x7f, sizeof (w)); //w记录两点之间最大的边权
	memset (f, 0x7f, sizeof (f)); //f记录两点之间最小的价值(ans)
	n = read (), m = read ();
	for (rg int i = 1; i <= n; i++)
	{
		a[i] = read ();
		s[i].c = a[i]; s[i].h = i;
	}
	sort (s + 1, s + 1 + n, cmp); //排个序
	ll u, v, l;
	for (rg int i = 1; i <= m; i++)
	{
		u = read (), v = read (), l = read ();
		w[u][v] = w[v][u] = l;
		f[u][v] = f[v][u] = l * max (a[u], a[v]);
	}
	for (rg int tt = 1; tt <= n; tt++)
	{
		int t = s[tt].h;
		for (rg int i = 1; i <= n; i++)
		  for (rg int j = 1; j <= n; j++)
		    if (i != t && i != j && j != t)
		      if (w[i][j] > max (w[i][t], w[t][j])) //如果要更新才更新
		    {
		    	w[i][j] = max (w[i][t], w[t][j]);
		    	f[i][j] = min (f[i][j], w[i][j] * max (a[i], max (a[t], a[j]))); //但是f也不一定会更新,所以取min
		    }
	}
	for (rg int i = 1; i <= n; i++)
	{
		for (rg int j = 1; j <= n; j++)
	  	{
	  		if (i == j) printf ("0");
	  		else if (f[i][j] == f[0][0]) printf ("-1");
	  		else write (f[i][j]);
	  		putchar (' ');
	  	}
	  	putchar (10);
	}
	return 0;
} 

你可能感兴趣的:(图论)