题意
监狱有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;
}