2017-10-7 vijos 无向图最短路径

描述

无向图最短路径问题,是图论中最经典也是最基础的问题之一。本题我们考虑一个有 nn 个结点的无向图 GG。
GG 是简单完全图,也就是说 GG 中没有自环,也没有重边,但任意两个不同的结点之间都有一条带权的双向边。
每一条边的边权是非负实数,但我们并不知道每一条边的具体边权。
好消息是我们知道 GG 中任意两点最短路径的长度d(i,j)d(i,j)。且保证至少有一种边权的分配方案满足得到的带权图中ii与jj的最短路长度恰好是d(i,j)d(i,j)。
下面是留给你的任务:对于任意一对点(i,j)(i,j),希望你能找出来所有合法的边权分配方案中ii和jj之间边权的最大值。
格式

输入格式

本题中,每一组数据都有多次询问,每一次询问分别给出了一个无向图GG。
输入的第一行是一个整数 tt,表示总共的询问个数。之后依次给出每一次询问。
对于每一次询问来说,第一行给出了 G 中结点总数 n。之后n行每行有n个整数,给出了一个n×n的矩阵 d,其中第ii行第jj列的整数对应 d(i,j)d(i,j)表示ii到jj的最短路径长度。
因为图GG是简单无向图,对角线元素d(i,i)d(i,i)总是0,且矩形是对称的(也就是说d(i,j)=d(j,i)d(i,j)=d(j,i))。
输出格式

对于每一次询问,若给定的图GG有nn个结点,则输出nn行,每行有nn个整数,描述了一个矩阵 aa。矩阵的第ii行第jj列表示连接ii和jj的边的最大可能边权。如果(i,j)(i,j)的边权可以任意大,则输出字符串infty表示无限。
矩阵的对角线没有实质性意义,请全输出00。因为GG是无向图,所以输出的矩阵aa应该也是对称的(即a(i,j)=a(j,i)a(i,j)=a(j,i))。
不难发现,因为给定的矩阵 dd 中每一个数字都是整数,所以最大可能边权总会是整数。
样例1

样例输入1

2
3
0 2 8
2 0 10
8 10 0
3
0 1 1
1 0 1
1 1 0

样例输出1

0 2 8
2 0 infty
8 infty 0
0 1 1
1 0 1
1 1 0

限制

对于 20\%20% 的数据,有 n = 3n=3。
对于 50\%50% 的数据,有 1≤n≤10。
对于 100\%100% 的数据,有 1≤n≤100,且所有询问中nn的和不超过 800800,对于所有的dd满足1≤d≤256。
每一组数据的时限为 0.5 秒。

题解
这个题挺有意思。
题目大意:给出的是所有两点间的最短路径,要求出图中两点的可能的最大边权,不会对最短路产生影响。
怎么考虑这个问题呢?首先我们把给出的最短路暂定为两条边之间的边权,然后跑floyed,要求是不能只经过一条路到达(即把两点间的最短路抹掉),如果这样得出的两点间的最短路于原来的最短路相等,那么直接连接这两个点的边可以任意大,否则就不变。
怎么能让他不能一条边到达呢?重新开一个数组记录。

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,d[101][101],m[101][101];

int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
                scanf("%d",&d[i][j]);
//      for (int i=1; i<=n; i++) m[i][i]=0x7fffffff;
        memset(m,0x7f,sizeof(m));
        for (int k=1; k<=n; k++)
            for (int i=1; i<=n; i++)
                for (int j=1; j<=n; j++)
                if (i!=j&&j!=k&&i!=k)
                    m[i][j]=min(m[i][j],d[i][k]+d[k][j]);
        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
            {
                if (m[i][j]==d[i][j]&&i!=j) d[i][j]=-1;
            }
        for (int i=1; i<=n; i++)
        {
            for (int j=1; j<=n; j++)
                if (d[i][j]==-1) printf("infty ");//==和=
                else printf("%d ",d[i][j]);
            printf("\n");
        }
    }
    return 0;
}

对noip来说,可能不需要那么多的算法。需要做到的是如何独立的思考问题,并将自己的想法转化成代码。同时还要做到认真,细致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值