地震

目录

目录

目录

题目

题目描述

输入

输出

样例输入

样例输出

题目解读

解析

思路

代码


题目

题目描述

农夫John的农场遭受了一场地震。有一些牛棚遭到了损坏,但幸运地,所有牛棚
间的路经都还能使用。FJ的农场有P个牛棚,编号1..P,  C条双向路经连接这些牛
棚,编号为1. . C。路经i连接牛棚ai和bi,路经可能连接ai到它自己,两个牛棚之
间可能有多条路经。农庄在编号为1的牛棚.,N头在不同牛棚的牛通过手机短信
reroortj告诉FJ它们的牛棚(repoortj)没有损坏,但是它们无法通过路经和没有损坏
的牛棚回到到农场。当FJ接到所有短信之后,找出最小的不可能回到农庄的牛榭
数目。这个数目包括损坏的牛棚。

输入

第1行:三个空格分开的数:P, C,和N
第2 ...C+1行:每行两个空格分开的数:ai和bi
第C+2 ...C+N+1行:每行一个数:reroortj

输出

第1行:一个数,最少不能回到农庄的牛的数目(包括损坏的牛棚)

样例输入

Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

4 3 1
1 2
2 3
3 4
3

样例输出

3

题目解读

首先,三号牛棚,尽管没被损坏,但是却不能回到第一个农庄,因而 2 号牛棚要么是损坏的,要么也回不到 1 号牛棚,因而我们可以断定 2 、3 号牛棚都回不了农庄,通过看图可知,4 号牛棚受到 3 号牛棚的影响也回不了农庄,因而 2  、3 、4 号牛棚都不能回去,固答案为 1

解析

如果要明白此题的做法,我们一定要搞清楚一个问题

如何让能更多的牛棚回到 1 号农庄?

显然,有的牛棚注定回不去!

我们就要让这些牛棚的影响范围尽量小

提供一种思路:

把与这些牛棚有直接关系的牛棚当做损坏的牛棚处理

我们举个例子,具体讲讲吧(在下面这幅图中,我们假设 2 是唯一的 reroortj)

一眼看去,删掉 3 即可,但是我们仔细算算,如果去掉 5 和 6 的话,岂不更好(4 还孤零零地在一旁呢)

因而,我们可以发现,既然:reroortj 周围的点定然不能到达 1 那么我们直接默认他们都是坏的吧,这样影响的肯定是最小的,就比如说,如果 2 走不到 1 ,那么从 1 到 2 的路径中,从破坏的牛棚以后的也走不到 1 号点,我们且设 3 为损坏的(它在 5 和 6 之前这是关键),这时 它还多连了 一个 4 ,这样答案就不能确保准确性。

  1. 在 1 - reroortj 的路径中,reroortj 不能回到 1 ,路径中的除 1 号和 reroortj  号节点外的任意一个节点也因此回不到 1 号节点。
  2. 在 1 - reroortj 的路径中,如果被损坏的节点越靠前他所影响到的节点也更多。

对于第二点,你只需知道 在  1 - reroortj 中,路径中的除 1 号和 reroortj  号节点外的任意一个节点的分支(也就是他所连的其他节点)也一定不能回到 1 号节点,否则 reroortj 就可以通过他回到一号节点了。

而又因为如果被损坏的牛棚越靠前,那么能回到 1 号农仓的牛棚就越少,不仅是他会多连几个点,而且在路径上,且在他后面的牛棚也会越多。

所以,在 reroortj 周围的牛棚被损坏答案更优。

明白了这些,我们只需要一个 dfs 搜索 1 号牛棚能遍历到的节点,我们用总数减掉被遍历过的个数即可,注意:被损坏的牛棚不能被遍历。

思路

我们将与 reroortj 相连的一些节点都标记为 true(就相当于他被遍历过),那么再用一个 ans 变量存遍历过几个数,最后用总数一间 ans 即为答案。

代码

#include<cstdio>
#include<vector>
#define M 30000 + 5
#define reg register
using namespace std;
  
int p,c,n,ans;
bool vis[M];
vector < int > G[M];
  
inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}
  
void dfs(int step){
    for (reg int i = 0;i < G[step].size(); ++ i){
        int x = G[step][i];
        if ( ! vis[x]){
            vis[x] = true;
            ++ ans;
            dfs(x);
        }
    }
}
  
int main(){
    read(p);
    read(c);
    read(n);
    vis[1] = true;
    for (reg int i = 1;i <= c; ++ i){
        int a,b;
        read(a);
        read(b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
    for (reg int i = 1;i <= n; ++ i){
        int a;
        read(a);
        for (reg int j = 0;j < G[a].size(); ++ j)
            vis[G[a][j]] = true;
    }
    dfs(1);
    printf("%d\n",p - ans - 1);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_43904786/article/details/86227098