题意
监狱有N条道路连接N + 1个交点,编号0至N,整个监狱被这些道路连在一起(任何2点之间都有道路),人们通过道路在交点之间走来走去。其中的一些交点只有一条路连接,这些点是监狱的出口。在各个交点中有M个点住着犯人(M <= N + 1),剩下的点可以安排警卫,有警卫把守的地方犯人无法通过。给出整个监狱的道路情况,以及犯人所在的位置,问至少需要安排多少个警卫,才能保证没有1个犯人能够逃到出口,如果总有犯人能够逃出去,输出-1。
题解
首先这是一颗树
为了方便,我们选择一个不是出口的地方作为根
不存在的情况只有一个,那就是只有两个点,特判就可以了
然后考虑怎么构造答案
对于一个点x,他是有犯人的
并且往儿子走,会走到出口,那么我们必须把所有儿子封住
然后他就只能往上走了
对于一个节点,如果他不是有犯人,但是儿子会有犯人走到他这里,并且他的别的儿子有出口,那么就把它封住
容易知道,这样肯定是最优的
然后就没有了。。
CODE:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=100005;
int n,m;
struct qq
{
int x,y,last;
}e[N*2];int num,last[N];
int d[N];
void init (int x,int y)
{
num++;d[x]++;
e[num].x=x;e[num].y=y;
e[num].last=last[x];
last[x]=num;
}
int rt;
bool ok[N];
int g[N];//有多少个
int h[N];//有多少个
int ans=0;
void dfs (int x,int fa)
{
bool ooo=false;
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
if (y==fa) continue;
ooo=true;
dfs(y,x);
if (g[x]==1)//如果这个点本来就有,那么就GG了
{
if (h[y]!=0)
{
h[y]=0;
ans++;
}
}
}
if (ooo==false)//叶子
{
// printf("%d %d\n",x,g[x]);
if (g[x]==1)
{
printf("-1");
exit(0);
}
h[x]=1;
return ;
}
if (g[x]==1)//堵死
{
h[x]=0;
return ;
}
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
if (y==fa) continue;
g[x]+=g[y];
h[x]+=h[y];
}
if (g[x]!=0&&h[x]!=0)
{
ans++;
g[x]=0;h[x]=0;
}
}
int main()
{
memset(ok,false,sizeof(ok));
num=0;memset(last,-1,sizeof(last));
scanf("%d%d",&n,&m);n++;
if (n==2)
{
if (m!=0) printf("-1");
else printf("0");
return 0;
}
for (int u=1;u<n;u++)
{
int x,y;
scanf("%d%d",&x,&y);x++;y++;
init(x,y);init(y,x);
}
for (int u=1;u<=n;u++)
if (d[u]!=1)
{rt=u;break;}
// printf("%d\n",rt);
for (int u=1;u<=m;u++)
{
int x;
scanf("%d",&x);x++;
g[x]=1;
}
dfs(rt,0);
printf("%d\n",ans);
return 0;
}