Codeforces543 B. Destroying Roads

传送门:>Here<

题意:给出一张无向图(边权为1),并给出两对起点和终点以及距离:s1,t1,l1; s2,t2,l2; 要求删除尽量多的边,使得dis(s1,t1)<=l1, dis(s2,r2)<=l2

解题思路

  首先我们会发现,由于边权都为1,删去一些边,某两点间的最短路肯定会随着删的边越来越多而越来越长(捷径被删了)

  因此我们会发现,要让边删的尽量多,最好最后只剩下最短路,其它边都剩下。换句话说,如果两条最短路不相交,那么最后只会剩下孤零零的两条链

  于是我们会发现,我们可以初步得到一个答案:$M - d(s1,t1) - d(s2,t2)$

  但这有可能不是最优的答案——两条最短路有可能有重叠。重叠的部分越长,答案就会越大也就是更优。并且很容易证明,重叠肯定只有连续的一段,而不会有间断的两断——因为如果需要有两断的话肯定不如连起来变为一段来的优。所以可以$O(n^2)$枚举重叠部分,验证一下就好了

Code

  用SPFA预处理出任意两点间的距离,注意数组要开$N*N$

  教训:当出现莫名其妙的错误的时候,首先检查数组有没有开错——例如,int开成bool,开得太小等等

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 3010;
const int MAXM = 5000010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar();
    if(c == ‘-‘) w = -1, c = getchar();
    while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w;
}
int N,M,x,y,s1,t1,l1,s2,t2,l2,top,sp1;
int first[MAXM*2],nxt[MAXM*2],to[MAXM*2],num_edge;
int d[MAXN][MAXN],inQ[MAXN],pre[MAXN],ans[MAXN],tmp[MAXN];
queue <int> q;
inline void add(int u, int v){
    to[++num_edge] = v;
    nxt[num_edge] = first[u];
    first[u] = num_edge;
}
inline void SPFA(int s, int c){
    for(int i = 0; i <= N; ++i) d[i][c] = INF;
    memset(inQ, 0, sizeof(inQ));
    d[s][c] = 0;
    q.push(s);
    int u,v;
    while(!q.empty()){
        u = q.front();q.pop();
        inQ[u] = 0;
        for(int i = first[u]; i; i = nxt[i]){
            v = to[i];
            if(d[u][c] + 1 < d[v][c]){
                d[v][c] = d[u][c] + 1;
                if(!inQ[v]){
                    inQ[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}
int main(){
//    freopen(".in","r",stdin);
    N=r,M=r;
    for(int i = 1; i <= M; ++i){
        x=r,y=r;
        add(x, y), add(y, x);
    }
    s1=r,t1=r,l1=r;
    s2=r,t2=r,l2=r;
    for(int i = 1; i <= N; ++i){
        SPFA(i, i);
    }
    if(d[s1][t1] > l1 || d[s2][t2] > l2){ printf("-1"); return 0; }
    int Ans = M - d[s1][t1] - d[s2][t2];
    if(Ans < 0) Ans = 0;
    for(int i = 1; i <= N; ++i){
        for(int j = 1; j <= N; ++j){
            if(i == j) continue;
            if(d[s1][i] + d[j][t1] + d[i][j] <= l1){
                if(d[s2][i] + d[j][t2] + d[i][j] <= l2){
                    Ans = Max(Ans, M - (d[s1][i]+d[i][j]+d[j][t1]+d[s2][i]+d[j][t2]));
                }
                if(d[s2][j] + d[i][t2] + d[i][j] <= l2){
                    Ans = Max(Ans, M - (d[s1][i]+d[i][j]+d[j][t1]+d[s2][j]+d[i][t2]));
                }
            }
            if(d[s1][j] + d[i][t1] + d[i][j] <= l1){
                if(d[s2][i] + d[j][t2] + d[i][j] <= l2){
                    Ans = Max(Ans, M - (d[s1][j]+d[i][j]+d[i][t1]+d[s2][i]+d[j][t2]));
                }
                if(d[s2][j] + d[i][t2] + d[i][j] <= l2){
                    Ans = Max(Ans, M - (d[s1][j]+d[i][j]+d[i][t1]+d[s2][j]+d[i][t2]));
                }
            }
        }
    }
    printf("%d", Ans);
    return 0;
}

原文地址:https://www.cnblogs.com/qixingzhi/p/9405596.html

时间: 2024-11-02 11:54:45

Codeforces543 B. Destroying Roads的相关文章

Codeforces544D:Destroying Roads(最短路)

In some country there are exactly n cities and m bidirectional roads connecting the cities. Cities are numbered with integers from 1 to n. If cities a and b are connected by a road, then in an hour you can go along this road either from city a to cit

Codeforces 543B Destroying Roads(最短路)

题意: 给定一个n个点(n<=3000)所有边长为1的图,求最多可以删掉多少条边后,图满足s1到t1的距离小于l1,s2到t2的距离小于l2. Solution: 首先可以分两种情况讨论: 1:假设最后留下的边是互不相交的两条路径.此时的答案是n-s1到t1的最短路径-s2到t2的最短路径. 2:假设最后留下的边有重合的一段,此时只要枚举重合的这一段的起点和终点,就可以判断.注意此时要考虑这两条路径经过枚举的两点的顺序. 限制的条件比较多,可以用来剪枝的条件也很多. 由于所有边的长度为1,用DF

Codeforces Round #302 (Div. 2) D. Destroying Roads 最短路 删边

题目:有n个城镇,m条边权为1的双向边让你破坏最多的道路,使得从s1到t1,从s2到t2的距离分别不超过d1和d2. #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include <stack> #in

codeforces 544 D Destroying Roads 【最短路】

题意:给出n个点,m条边权为1的无向边,破坏最多的道路,使得从s1到t1,s2到t2的距离不超过d1,d2 因为最后s1,t1是连通的,且要破坏掉最多的道路,那么就是求s1到t1之间的最短路 用bfs求出任意两个顶点之间的距离, 如果d[s1][t1]>d1||d[s2][t2]>d2,那么不可能 然后就枚举重叠的区间(就像题解里面说的"H"形一样) 如果枚举区间是1--n,1--i的话,需要交换四次 如果枚举区间是1--n,1--n的话,则只需要交换一次就可以了 看的这一

CF543B Destroying Roads 枚举 + 思维 + BFS

Code: #include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s".in","r",stdin) #define maxn 3002 using namespace std; queue<int>Q; vector<int>G[maxn]; int n,m,s1,t1,l1,s2,t2,l2; int vis[maxn],d[maxn][m

所谓的日常 #5 - 發矯詔諸鎮應曹公 破關兵三英戰呂布

大家期末加油~不挂科后面才能好好的做题哇=w= div.2 CodeForces 330A Cakeminator 给一个r(<=10)行c(<=10)列的矩形蛋糕,每次你会选择一行或一列全部吃掉.有些位置有草莓,然而你不想吃草莓,问最多能吃到多少蛋糕. 如果我们吃了a行b列的话,可以这么算:先数a * m个,再数b * n个,然后把重复算的部分去掉,也就是a * b个. 或者另外开一个标记数组,把吃掉的位置标记一下也是可以的.怎么写高兴怎么来. 1 #include <stdio.h&

Codeforces Round #302 (Div. 2) (ABCD题解)

比赛链接:http://codeforces.com/contest/544 A. Set of Strings time limit per test:1 second memory limit per test:256 megabytes You are given a string q. A sequence of k strings s1,?s2,?...,?sk is called beautiful, if the concatenation of these strings is

Codeforces Round #302 解题报告

感觉今天早上虽然没有睡醒但是效率还是挺高的... Pas和C++换着写... 544A. Set of Strings You are given a string q. A sequence of k strings s1, s2, ..., sk is called beautiful, if the concatenation of these strings is string q(formally, s1 + s2 + ... + sk = q) and the first chara

HDUOJ----2485 Destroying the bus stations

Destroying the bus stations Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2072    Accepted Submission(s): 647 Problem Description Gabiluso is one of the greatest spies in his country. Now he'