【lnoi2013】最小距离之和

本文介绍了一种利用Floyd算法解决通信渠道破坏问题的方法。通过预先处理所有可能的渠道破坏情况,实现高效的路径更新与最短路径计算。适用于解决大规模网络中节点间最短路径的动态变化问题。

题目描述 Description

DQ星球的世界末日就要到了,可是诺亚方舟还没有制造完成。为了制造诺亚方舟这个星球上的所有国家都站在统一战线。现在一共有n个国家,一个国家到另一个国家都有一条且仅有一条通信渠道,且这个渠道有一个距离,这样就形成了一个有向完全图。 世界末日的预兆已经来了,世界上很多东西都在遭到不明原因的破坏,包括这些通信渠道。现在为了联合制造出诺亚方舟,需要统计所有国家对(a到b和b到a是不同的)之间通信最短距离之和。即需要求出表示i国家与j国家之间的最小距离。可是每隔一段时间就有一些渠道会被破坏,现在DQ星球的首领急需要你来解决这个问题。

输入描述 Input Description

对于每组数据,第一行是一个n,表示有n个国家,接下来有n行,每有n个整数。第i行第j列的数字表示国家i到国家j的通信渠道距离(距离不大于10000)。接下来是一个数字m,表示在可以预知的未来中会有m次破坏会施加到通信渠道中,每次破坏只能破坏一条渠道,一条渠道可以被破坏多次, 但是第一次破坏这条渠道就无法再发送信息。接下来有m行,每行两个整数a、b,表示国家a到国家b的通信渠道遭到破坏。

输出描述 Output Description

对于每组数据,输出m行,第i行表示第i次破坏后对应的答案是多少。如果存在两个国家无法相互到达,输出INF。

样例输入 Sample Input

3

0 1 1

1 0 1

1 1 0

4

1 2

1 2

2 3

2 1

样例输出 Sample Output

7

7

8

INF

数据范围及提示 Data Size & Hint

40%的数据中1 < n<=50,1< m<=50;

100%的数据中1 < n<=200,1< m<=200;


终于找到一道floyd!离线!!

首先,先把该破坏的都破坏了,再对剩下的邻接矩阵做floyd。
然后现在就拿到了第m次破坏后的答案。
之后从m-1次开始往前把边恢复回去。由于现在的图只能被这个被破坏的边更新,所以就n^2枚举点,更新邻接矩阵,然后再累加,得到m-1次破坏的答案,以此类推。

代码:

#include<cstdio> 
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int size=450;
const int INF=23333333;
int G[size][size];

struct haha{
    int f,t,d;
    int ans;
}ans[size];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&G[i][j]);
        }
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&ans[i].f,&ans[i].t);
        ans[i].d=G[ans[i].f][ans[i].t];
        G[ans[i].f][ans[i].t]=INF;
    }
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
            }
        }   
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            ans[m].ans+=G[i][j];
        }
    }
    for(int k=m;k>=1;k--)
    {
        int f=ans[k].f;
        int t=ans[k].t;
        int d=ans[k].d;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                G[i][j]=min(G[i][j],G[i][f]+d+G[t][j]);
            }
        }   
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                ans[k-1].ans+=G[i][j];
            }
        }       
    }
    for(int i=1;i<=m;i++)
    {
        if(ans[i].ans>=INF) puts("INF");
        else printf("%d\n",ans[i].ans);
    }
    return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值