简单树形dp!
§题目大意:
§
一城堡的所有的道路形成一个n个节点的树,如果在一个节点上放上一个士兵,那么和这个节点相连的边就会被看守住,问把所有边看守住最少需要放多少士兵。 dproot[ i ]
§
all[ i ]表示看守住整个以i为根的子树需要多少士兵。然后直接树形DP就ok了,不过某人给了个很好的思考题,假如把守边改为守点,该怎样处理呢?
我想了一个方法,不知可行不可行:
dp[i][1]表示i节点处 放士兵使 以i为根的树都能守住 ,dp[i][1]=1+min(dp[j][1],dp[j][0]);
dp[i][0]表示i节点处不放士兵使 以i为根的树都能守住,
{
如果其孩子节点中任意一个j能满足 dp[j][1]<dp[j][0] ,则dp[i][0]=dp[i][1]-1;
否则 dp[i][0]=dp[i][1];
}
不知道这种思想是否正确,求路过的大牛给与正确的解释。
(哎,忽然间我发现了上面的思路有漏洞)
贴一下这道题目的代码:
View Code
1 # include<stdio.h>
2 # include<string.h>
3 # include<stdlib.h>
4 # define N 1505
5 struct node{
6 int from,to,next;
7 }edge[N*2];
8 int head[N],tol,dproot[N],all[N];
9 void add(int a,int b)
10 {
11 edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
12 }
13 int min(int a,int b)
14 {
15 return a<b?a:b;
16 }
17 void dfs(int root,int father)
18 {
19 int j,u,sum;
20 dproot[root]=1;
21 sum=0;
22 for(j=head[root];j!=-1;j=edge[j].next)
23 {
24 u=edge[j].to;
25 if(u!=father)
26 {
27 dfs(u,root);
28 dproot[root]+=all[u];
29 sum+=dproot[u];
30 }
31 }
32 all[root]=min(sum,dproot[root]);
33 }
34 int main()
35 {
36 int i,j,n,num,ans1,ans2;
37 while(scanf("%d",&n)!=EOF)
38 {
39 memset(head,-1,sizeof(head));
40 tol=0;
41 for(i=0;i<n;i++)
42 {
43 scanf("%d:(%d)",&ans1,&num);
44 for(j=1;j<=num;j++)
45 {
46 scanf("%d",&ans2);
47 add(ans1,ans2);
48 add(ans2,ans1);
49 }
50 }
51 dfs(0,0);
52 printf("%d\n",min(dproot[0],all[0]));
53 }
54 return 0;
55 }