HDOJ 4650: Minimum Average Weight Path

来源:互联网 发布:千里眼软件 编辑:程序博客网 时间:2024/05/14 16:47

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4650


题目大意:

给定一个无重边的有向图,

求全源最小平均权值路径。

最小平均权值路径的定义是,路径总权值 / 路径上的边数最小。


算法:

题目应当分为两种情况:

两点间的路径上可能存在负环,如果一条路径沿着这个负环不断走下去,那么最终的平均值一定是趋于这个负环的平均权值。

无负环,那么这个显然很好求。

做这道题首先要知道一种用矩阵求两点间恰好K条边的最短路径的方法。不清楚的话建议去做POJ 3613。

首先,利用矩阵乘法,由1~n枚举路径长度,然后根据此时各点间的最短路 / 路径长度,不断更新此时的最小平均权值路径。

然后,讨论图上的各个环,如果某点有负环,那么对于任两个可以到达这个点的点对,这个负环的平均权值可能会更新这个点对上的最小平均权值。


PS:这算是我做过的少有的,在赛场上写出来且代码量极小,却可以把它归为中高级图论的题吧。笑。


代码如下:

#include<cstdio>#include<iostream>#include<algorithm>#include<sstream>#include<cstdlib>#include<cstring>#include<string>#include<climits>#include<cmath>#include<queue>#include<vector>#include<stack>#include<set>#include<map>#define INF 0x3f3f3f3f#define eps 1e-8using namespace std;const int MAXN=110;int vis[MAXN][MAXN];double ans[MAXN][MAXN];int tot;struct Matrix{    int h,w;    int mx[MAXN][MAXN];    Matrix operator* (const Matrix& b) const    {        Matrix tmp;        memset(tmp.mx,INF,sizeof(tmp.mx));        tmp.h=h;        tmp.w=b.w;        for (int i=1; i<=h; i++)        {            for (int j=1; j<=b.w; j++)            {                for (int k=1; k<=w; k++)                {                    if(vis[i][k]==-1||tot<vis[i][k])                    {                        continue;                    }                    if(vis[k][j]==-1||tot<vis[k][j])                    {                        continue;                    }                    tmp.mx[i][j]=min(tmp.mx[i][j],mx[i][k]+b.mx[k][j]);                }            }        }        return tmp;    }};Matrix g,f;int main(){    int n, m;    while(scanf("%d %d",&n, &m)==2)    {        memset(g.mx,INF,sizeof(g.mx));        g.h=g.w=n;        for(int i=1; i<=n; i++)        {            for(int j=1; j<=n; j++)            {                ans[i][j]=1e7;            }        }        memset(vis,-1,sizeof(vis));        for(int i=0; i<m; i++)        {            int u,v;            scanf("%d%d",&u,&v);            scanf("%d",&g.mx[u][v]);            vis[u][v]=1;        }        for(int k=1; k<=n; k++)        {            for(int i=1; i<=n; i++)            {                if(vis[i][k]==-1)                {                    continue;                }                for(int j=1; j<=n; j++)                {                    if(vis[k][j]==-1)                    {                        continue;                    }                    vis[i][j]=(vis[i][j]==-1)?vis[i][k]+vis[k][j]:min(vis[i][j],vis[i][k]+vis[k][j]);                }            }        }        f=g;        for(tot=1; tot<=n; tot++)        {            for(int i=1; i<=n; i++)            {                for(int j=1; j<=n; j++)                {                    if(vis[i][j]!=-1&&tot>=vis[i][j])                    {                        ans[i][j]=min(ans[i][j],(double)f.mx[i][j]/tot);                    }                }            }            f=f*g;        }        for(int k=1; k<=n; k++)        {            for(int i=1; i<=n; i++)            {                if(vis[i][k]==-1)                {                    continue;                }                for(int j=1; j<=n; j++)                {                    if(vis[k][j]==-1||vis[k][k]==-1)                    {                        continue;                    }                    ans[i][j]=min(ans[i][j],ans[k][k]);                }            }        }        for(int i=1; i<=n; i++)        {            for(int j=1; j<=n; j++)            {                if(j>1)                {                    putchar(' ');                }                if(vis[i][j]!=-1)                {                    printf("%.3lf",ans[i][j]);                }                else                {                    printf("NO");                }            }            puts("");        }    }    return 0;}


原创粉丝点击