目录
目录
题目
题目描述
农夫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 - reroortj 的路径中,reroortj 不能回到 1 ,路径中的除 1 号和 reroortj 号节点外的任意一个节点也因此回不到 1 号节点。
- 在 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;
}