51nod 1299 监狱逃离

题目描述

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

Input

第1行:2个数N, M中间用空格分隔,N表示道路的数量,M表示犯人的数量(1<= N <= 100000, 0 <= M <= N + 1)。
之后N行:每行2个数S, E中间用空格分隔,表示点编号为S的点同编号为E的点之间有道路相连。(0 <= S, E <= N)。
之后的M行,每行1个数Pi,表示编号为Pi的点上有犯人。

Output

输出1个数对应最少需要多少警卫才能不让犯人逃出监狱。

Input示例

8 2
0 1
1 2
2 3
3 4
3 5
2 6
6 8
6 7
1
6

Output示例

4

Solution

典型的一道树形dp,听说有人跑20万网络流过了Orz
使得任意一个出口为根节点,逃离方向就固定为向上到根或向下到叶子节点
考虑一个点的3种状态:
f[i],表示以i为根的子树的状态
f[i]=0,子树中的点无法到达这个点,且不存在一条从这点到叶子节点的路径。 
f[i]=1,子树中的点无法到达这个点,但存在一条从这点到叶子节点的路径。 
f[i]=2,子树中的点可以到达这个点,且不存在一条从这点到叶子节点的路径

i点的儿子的状态都为0,则f[i]=0
儿子的状态有1也有2,则i点必须放,ans++(以为2点可以通过i点到叶子节点)
若i有逃犯则儿子中有1状态的都要被放,ans加上儿子为1的个数
剩下的儿子状态单一,直接转移即可。

 

Code

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define fo(i,a,b) for(int i=a;i<=b;i++)
 6 #define fd(i,a,b) for(int i=a;i>=b;i--)
 7 #define fh(i,x) for(int i=head[x];i;i=next[i])
 8 typedef long long LL;
 9 using namespace std;
10 inline int max(int x,int y) {return (x<y)?y:x;}
11 inline int min(int x,int y) {return (x<y)?x:y;}
12 inline int read() {
13     int x=0,f=1;char ch=getchar();
14     while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
15     while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
16 }
17 const int N=1e5+5;
18 int n,m,tot,x,y,ans,d[N],f[N];
19 int to[N*2],next[N*2],head[N];
20 bool bz[N];
21 void add(int x,int y) {to[++tot]=y;next[tot]=head[x];head[x]=tot;}
22 void dfs(int x,int y) {
23     int s[3];memset(s,0,sizeof(s));
24     fh(i,x) if(to[i]!=y) dfs(to[i],x),s[f[to[i]]]++;
25     if (bz[x]) ans+=s[1],f[x]=2;
26     else if(s[1]&&s[2]) ans++,f[x]=0;
27     else if(s[1]) f[x]=1;
28     else if(s[2]) f[x]=2;
29     else if(s[0]) f[x]=0;
30 }
31 int main() {
32     n=read(),m=read(),n++;
33     fo(i,1,n-1) x=read(),y=read(),x++,y++,add(x,y),add(y,x),d[x]++,d[y]++;
34     fo(i,1,n) f[i]=1;
35     fo(i,1,m) {
36         x=read(),x++;
37         if(d[x]==1) {printf("-1\n");return 0;}
38         bz[x]=1;
39     }
40     int root=1;
41     fo(i,1,n) if(d[i]==1) {root=i;break;}
42     dfs(root,0);
43     if(f[root]==2) ans++;
44     printf("%d\n",ans);
45 }

 

posted @ 2017-11-29 22:27  _patrick  阅读(211)  评论(0编辑  收藏  举报