51NOD - 破坏道路(最短路+枚举)

522 篇文章 3 订阅
71 篇文章 0 订阅

题目链接:https://www.51nod.com/Challenge/Problem.html#!#problemId=1444

  • 时间限制 2 秒 空间限制 131,072 KB

题目描述

在某一个国家,那儿有n个城市,他们通过m条双向道路相连。城市从1到n编号。如果城市a和b通过一条道路直接相连,那么他们之间的距离就是一个小时。这个国家的道路网络可以允许你从任意一个城市到达另外的城市。
现在你要破坏尽可能多的道路,但是要保证从城市s1到t1不超过l1小时,并且从城市s2到t2不超过l2小时。
输出最多可以破坏的道路数目,如果没有解,请输出-1

输入

单组测试数据。
第一行有两个整数n,m(1 ≤ n ≤ 3000, n-1 ≤ m ≤ min(3000,n*(n-1)/2))。
接下来m行,每行有两个整数 ai, bi (1 ≤ ai, bi ≤ n, ai ≠ bi),表示ai和bi之间有一条道路。
输入保证是一个连通图。
最后两行每行有三个整数s1, t1, l1和 s2, t2, l2, (1 ≤ si, ti ≤ n, 0 ≤ li ≤ n)。

输出

输出一个整数,表示最多可以破坏的道路数目,如果没有解,输出-1。

输入样例

5 4
1 2
2 3
3 4
4 5
1 3 2
3 5 2

输出样例

0

解题思路

先将两两之间的最短距离都求出来,然后将题目的s1到t1和s2到t2两个的最短距离加起来,但是这个只是两个最短距离的和,但不是最小的,因为还有可能有重复的路径他们都走过,所以还可以减去重复的才是最短的,我们可以枚举重叠的路径。

#include <queue>
#include <cstring>
#include <iostream>
using namespace std;
struct edge {
    int next[3005], front;
}map[3005];
int dis[3005][3005], vis[3005];
int main()
{
    int n, m, ans, a, b, t, v, s1, t1, l1, s2, t2, l2;
    while (~scanf("%d%d", &n, &m))
    {
        memset(dis, 0, sizeof(dis));
        memset(map, 0, sizeof(map));
        for (int i = 0; i < m; i++)
        {
            scanf("%d%d", &a, &b);
            map[a].next[++map[a].front] = b;
            map[b].next[++map[b].front] = a;
        }
        scanf("%d%d%d", &s1, &t1, &l1);
        scanf("%d%d%d", &s2, &t2, &l2);
        for (int i = 1; i <= n; i++)
        {
            queue <int> Q;
            memset(vis, 0, sizeof(vis));
            Q.push(i);
            vis[i] = 1;
            while (!Q.empty())
            {
                t = Q.front();
                for (int j = 1; j <= map[t].front; j++)
                {
                    v = map[t].next[j];
                    if (!vis[v])
                    {
                        vis[v] = 1;
                        Q.push(v);
                        dis[i][v] = dis[i][t] + 1;
                    }
                }
                Q.pop();
            }
        }
        if (dis[s1][t1] > l1 || dis[s2][t2] > l2)
        {
            printf("-1\n");
            continue;
        }
        ans = dis[s1][t1] + dis[s2][t2];
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (dis[s1][i] + dis[i][j] + dis[j][t1] <= l1 && dis[s2][i] + dis[i][j] + dis[j][t2] <= l2)
                    ans = min(ans, dis[s1][i] + dis[j][t1] + dis[s2][i] + dis[j][t2] + dis[i][j]);
                if (dis[s1][i] + dis[i][j] + dis[j][t1] <= l1 && dis[t2][i] + dis[i][j] + dis[j][s2] <= l2)
                    ans = min(ans, dis[s1][i] + dis[j][t1] + dis[t2][i] + dis[j][s2] + dis[i][j]);
                if (dis[t1][i] + dis[i][j] + dis[j][s1] <= l1 && dis[s2][i] + dis[i][j] + dis[j][t2] <= l2)
                    ans = min(ans, dis[t1][i] + dis[j][s1] + dis[s2][i] + dis[j][t2] + dis[i][j]);
                if (dis[t1][i] + dis[i][j] + dis[j][s1] <= l1 && dis[t2][i] + dis[i][j] + dis[j][s2] <= l2)
                    ans = min(ans, dis[t1][i] + dis[j][s1] + dis[t2][i] + dis[j][s2] + dis[i][j]);
            }
        }
        printf("%d\n", m - ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ityanger

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值