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

来源:互联网 发布:查看sql文件乱码 编辑:程序博客网 时间:2024/05/17 04:10

题目大意:

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

解题思路:

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

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<ctime>#define ll long longusing 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.val<b.val;    }}a[N];int 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<<f[i][j]<<' ';            else cout<<-1<<' ';        cout<<'\n';    }    return 0;           }