Codeforces Round #302 (Div. 1) B Destroying Roads(最短路+枚举)

关键词:bfs求单源最短路径、O(n^2)枚举相交路径
题意:在一个有向图中删除尽量多的边使得s1->t1,s2->t2的最短路分别不大于l1和l2
解法:
1.bfs求单源最短路径。遍历所有的顶点,求出所有点源最短路
2.枚举两条道路的相交路径。相交路径仅加一次即可

思路分析:
从删边后的结果出发,s1->t1,s2->t2有一段相交路径,其余部分不相交。要使删边最大,就要使留下的边长和最小。因此
s1->t1,s2->t2均由三条最短路组成。枚举中间的那条最短路两端点维护剩余图的最小边长和。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define mem(a,b) memset(a,sizeof(a),b)
#define ll long long
using namespace std;

const int maxn = 3000+10;

int n,m;
vector<int> e[maxn];
int s[2],t[2],l[2];
int ans;
int d[maxn][maxn];

void bfs(int x){
    queue<int> q;
    for(int i=1;i<=n;i++) d[x][i]=-1;
    q.push(x),d[x][x]=0;
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=0;i<e[u].size();i++){
            int v=e[u][i];
            if(d[x][v]==-1){
                d[x][v]=d[x][u]+1;
                q.push(v);
            }
        }
    }
}

int main(){
    //freopen("a.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        e[a].push_back(b),e[b].push_back(a);
    }
    for(int i=1;i<=n;i++) bfs(i);
    for(int i=0;i<2;i++) scanf("%d%d%d",&s[i],&t[i],&l[i]);
    if(d[s[0]][t[0]]>l[0]||d[s[1]][t[1]]>l[1]){
        printf("-1\n");
        return 0;
    }
    ans=d[s[0]][t[0]]+d[s[1]][t[1]];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int l1=d[s[0]][i]+d[i][j]+d[j][t[0]],l2=d[s[0]][j]+d[j][i]+d[i][t[0]];
            int l3=d[s[1]][i]+d[i][j]+d[j][t[1]];
            if(l1<=l[0]&&l3<=l[1]) ans=min(ans,l1+d[s[1]][i]+d[j][t[1]]);
            if(l2<=l[0]&&l3<=l[1]) ans=min(ans,l2+d[s[1]][i]+d[j][t[1]]);
        }
    }
    printf("%d\n",m-ans);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值