您的位置:首页 > 其它

51nod 1299 监狱逃离 树形dp

2017-10-30 10:52 260 查看

题意

监狱有N条道路连接N + 1个交点,编号0至N,整个监狱被这些道路连在一起(任何2点之间都有道路),人们通过道路在交点之间走来走去。其中的一些交点只有一条路连接,这些点是监狱的出口。在各个交点中有M个点住着犯人(M <= N + 1),剩下的点可以安排警卫,有警卫把守的地方犯人无法通过。给出整个监狱的道路情况,以及犯人所在的位置,问至少需要安排多少个警卫,才能保证没有1个犯人能够逃到出口,如果总有犯人能够逃出去,输出-1。

1<= N <= 100000

分析

据说直接上最小割可以艹过去。。。

找一个非叶节点当根,就可以树形dp。

设f[x,0]表示以x为根的树,有犯人走上来且没有到出口的道路。

f[x,1]表示以x为根的树,没有犯人可以走上来且没有到出口的道路。

f[x,2]表示以x为根的树,没有犯人可以走上来且有到出口的道路。

随便转移一下即可。

注意叶节点也犯人点要分类讨论一下。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005;
const int inf=10000000;

int n,m,d
,f
[3],last
,cnt,gui
;
struct edge{int to,next;}e[N*2];

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

void dfs(int x,int fa)
{
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa) continue;
dfs(e[i].to,x);
}
if (gui[x])
{
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa) continue;
f[x][0]+=min(f[e[i].to][0],f[e[i].to][1]);
}
f[x][1]=f[x][2]=inf;
}
else if (d[x]==1) f[x][0]=f[x][1]=1,f[x][2]=0;
else
{
int s1=0,s2=1;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa) continue;
f[x][0]+=min(f[e[i].to][0],f[e[i].to][1]);
s1+=f[e[i].to][1];s2+=min(f[e[i].to][0],min(f[e[i].to][1],f[e[i].to][2]));
f[x][2]+=min(f[e[i].to][1],f[e[i].to][2]);
}
f[x][1]=min(s1,s2);f[x][0]=min(f[x][0],s2);f[x][2]=min(f[x][2],s2);
}
}

int main()
{
n=read()+1;m=read();
for (int i=1;i<n;i++)
{
int x=read()+1,y=read()+1;
addedge(x,y);d[x]++;d[y]++;
}
while (m--) {int x=read()+1;gui[x]=1;}
for (int i=1;i<=n;i++) if (d[i]==1&&gui[i]) {puts("-1");return 0;}
int root=0;
for (int i=1;i<=n;i++) if (d[i]>1) {root=i;break;}
dfs(root,0);
printf("%d",min(f[root][0],min(f[root][1],f[root][2])));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: