道路阻塞(rblock)

题目描述

每天早上,约翰都要从他的家里步行去农场,他途中可能要经过其他的一些地方。我们把这些地方和路抽象成一张图,这张图里有 N 个点,共有 M 条边(每条边都是双向边),每条边都有一个长度,约翰的家在第 1 个点,农场在第 N 个点,两个点之间没有重复的边,并且这个图是一个连通图,每次约翰从家里到农场总会选一条最短的路径走。

但是约翰的奶牛们老是给约翰捣乱,奶牛们计划在其中某条路上放一些干草堆来阻碍约翰的行走,干草堆放在哪条路上,那条边的长度就相当于增加了一倍。现在,奶牛们想要知道如何选择一条边放干草堆,才能使约翰从家里到农场花费的路程增加最多。

输入

从文件 rblock.in 中读入数据。

从文件 rblock.in 中读入数据。

第一行是两个正整数 N 和 M。

接下来 M 行,每行三个整数 a,b,c 表示点 a 到点 b 的距离是 c。

输出

输出到文件 rblock.out 中。

输出到文件 rblock.out 中。

输出从家里到农场的最短路径最多会增加的距离。

样例数据
输入 #1 复制
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
输出 #1 复制
2
数据范围限制

对于 100% 的数据,满足 1<=N<=250,1<=M<=25000,1<=c<=10^6。

提示

样例1解释

当奶牛们把干草堆放在 3-4 的边上时,3-4 的边的长度相当于从 3 变到 6,约翰的最短路径就变成了 1-3-5,总共的距离等于 1+7=8,比原来的最短路长度增加了 2。

思路:打一下暴力,原本以为迪杰斯特拉会超时,没想到AC了,先算一次迪杰斯特拉,算出原本的最短路,再一条一条边乘2,算出之后的最短路的最小值,最后输出相减后的结果。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,ans,sum;
int mi[255],nx[25005],
f[255][255],to[25005];
bool c[255];
int main()
{
    freopen("rblock.in","r",stdin);
    freopen("rblock.out","w",stdout);
    memset(f,0x3f3f3f,sizeof(f));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        f[x][y]=f[y][x]=z,nx[i]=x,to[i]=y;
    }
    memset(mi,0x7f7f,sizeof(mi));
    mi[1]=0;
    for(int i=1;i<=n;i++)
    {
        int x=-1;
        for(int j=1;j<=n;j++)
        {
            if(c[j]==0&&(x==-1||mi[j]<mi[x]))
            {
                x=j;
            }
        }
        if(x==-1)
        {
            break;
        }
        c[x]=1;
        for(int j=1;j<=n;j++)
        {
            if(c[j]==0&&mi[j]>f[x][j]+mi[x])
            {
                mi[j]=f[x][j]+mi[x];
            }
        }        
    }
    sum=mi[n];
    for(int i=1;i<=m;i++)
    {
        memset(mi,0x7f7f,sizeof(mi));
        memset(c,0,sizeof(c));
        mi[1]=0,f[nx[i]][to[i]]*=2,f[to[i]][nx[i]]*=2;
        for(int i=1;i<=n;i++)
        {
            int x=-1;
            for(int j=1;j<=n;j++)
            {
                if(c[j]==0&&(x==-1||mi[j]<mi[x]))
                {
                    x=j;
                }
            }
            if(x==-1)
            {
                break;
            }            
            c[x]=1;
            for(int j=1;j<=n;j++)
            {
                if(c[j]==0&&mi[j]>f[x][j]+mi[x])
                {
                    mi[j]=f[x][j]+mi[x];
                }
            }        
        }    
        ans=max(ans,mi[n]),f[nx[i]][to[i]]/=2,f[to[i]][nx[i]]/=2;
    }
    printf("%d",ans-sum);
    return 0; 
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值