NOIP模拟 路径统计 【弗洛伊德算法】

题目大意:

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

解题思路:

看到n<=500就想到了弗洛伊德算法,但怎么处理呢?
普通的弗洛伊德算法是按点的标号顺序枚举k的,这里我们可以按点权从小到大的顺序枚举k,那么计算时任意两点间的最大点值只能是i,j,k中的一个,现在就只用维护i,j之间路径的最大边的最小值即可。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=505,inf=2e9;
const ll INF=2e18;
int n,m;
struct node
{
    int val,id;
    inline friend bool operator <(const node &a,const node &b)
    {
        return a.valint g[N][N];
ll f[N][N];


int main()
{
    //freopen("path.in","r",stdin);
    //freopen("path.out","w",stdout);
    int x,y,z,mx;
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=INF,g[i][j]=inf;
    for(int i=1;i<=n;i++)
        f[i][i]=g[i][i]=0,a[i].val=getint(),a[i].id=i;
    while(m--)
    {
        x=getint(),y=getint(),z=getint();
        g[x][y]=g[y][x]=z;
    }
    sort(a+1,a+n+1);
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                x=a[i].id,y=a[j].id,z=a[k].id;
                g[x][y]=min(g[x][y],max(g[x][z],g[z][y]));
                if(i<=k&&j<=k)f[x][y]=min(f[x][y],1ll*a[k].val*g[x][y]);//只用讨论i,j均小于k的情况,因为i,j>k的话下次k循环到i,j时也会处理。
            }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            if(f[i][j]!=INF)cout<' ';
            else cout<<-1<<' ';
        cout<<'\n';
    }
    return 0;           

}

你可能感兴趣的:(最短路)