poj1463

状态设计:

      1、dp[i][0],表示在结点 i 没放置士兵的情况下,看住以结点 i 为根的子树的所有边所需的最少士兵;

      2、dp[i][1],表示在结点 i 放置士兵的情况下,看住以结点 i 为根的子树的所有边所需的最少士兵。

状态转移:

      1、dp[i][0]=∑dp[j][1],j 是 i 的儿子结点;(根结点不放士兵时,与其相连的边必须由儿子结点来看守)

      2、dp[i][1]=dp[i][1]+∑ ( MIN ( dp[j][0] , dp[j][1] ) ),j 是 i 的儿子结点。 (根结点放士兵时,儿子结点可放可不放)

初始化:  d[i][0]=0,d[i][1]=1,i是每一个节点

 1 #include <stdio.h>
 2 #include <cstring>
 3 struct node
 4 {
 5     int u;
 6     int next;
 7 };
 8 
 9 int min(int a ,int b)
10 {
11     return a>b?b:a;
12 }
13 
14 node edge[1505*10];
15 int visited[1505];
16 int dp[1505][2];
17 int head[1505];
18 int count=0;
19 int root=-1;
20 void addEdge(int c , int  d)
21 {
22      edge[count].u=d;
23      edge[count].next=head[c];
24      head[c]=count++;
25 
26      edge[count].u=c;
27      edge[count].next=head[d];
28      head[d]=count++;
29 }
30 
31 void dfs(int u)
32 {
33     visited[u]=1;
34     dp[u][1]=1;
35     dp[u][0]=0;
36     for(int i=head[u];i!=-1;i=edge[i].next)
37     {
38         int v=edge[i].u;
39         if(visited[v]==0)
40         {
41             dfs(v);
42             dp[u][0]=dp[u][0]+dp[v][1];
43             dp[u][1]=dp[u][1]+min(dp[v][1],dp[v][0]);
44         }
45     }
46 }
47 
48 
49 
50 void init()
51 {
52     count=0;
53     root=-1;
54     memset(head,-1,sizeof(head));
55     memset(dp,0,sizeof(dp));
56     memset(visited,0,sizeof(visited));
57 }
58 
59 
60 
61 int main()
62 {
63     int n;
64     int count,child,s;
65     while(scanf("%d",&n)!=EOF)
66     {
67         init();
68         for(int i=0;i<n;i++)
69         {
70             scanf("%d:(%d)",&s,&count);
71             if(root==-1) root=s;
72             for(int j=0;j<count;j++)
73             {
74                 scanf("%d",&child);
75                 addEdge(s,child);
76             }
77         }
78         dfs(root);
79         printf("%d\n",min(dp[root][0],dp[root][1]));
80     }
81     return 0;
82 }

代码中的东西好多都是前面的几个同类型的题用到的

这里比较重要的就是dfs里面的dp了,根据状态转移,按照深度优先遍历从底向上依次更新

 

还要补充点,这里的建树还可以用其他方法,在这里贴一个,建树的方法可以学习一下,不过原理都是一样的,用的都是邻接表示法,只不过下面的代码用了vector,这个个人感觉比较慢,初次之外还可以用指针来表示邻接表,数据结构这本书上是这么写的

View Code
 1 #include<iostream>
 2 #include<fstream>
 3 #include<vector>
 4 
 5 using namespace std;
 6 
 7 
 8 typedef struct e{
 9     int data;
10     vector<int> a;
11 }e;
12 
13 e edge[1501];
14 int dp[1501][2];
15 int v[1501][2];
16 int n;
17 int solve(int);
18 
19 int solve1(int s){
20     int i,j,k;
21     if(v[s][1]) return dp[s][1];
22     v[s][1]=1;
23     dp[s][1]=1;
24     k=edge[s].a.size();
25     for(i=0;i<k;i++)
26     {
27         j=edge[s].a[i];
28         dp[s][1]+=solve(j);
29     }
30     return dp[s][1];
31 }
32 
33 int solve(int s){
34     int i,j,k,t=0;
35     if(v[s][0]) return dp[s][0];
36     v[s][0]=1;
37     k=edge[s].a.size();
38     for(i=0;i<k;i++)
39     {
40         j=edge[s].a[i];
41         t+=solve1(j);
42     }
43     dp[s][0]=min(solve1(s),t);
44     return dp[s][0];
45 }
46 
47 void read(){
48 //    ifstream cin("in.txt");
49     int i,j,k,s,t;
50     char c;
51     while(scanf("%d",&n)!=EOF)
52     {
53         for(i=0;i<=n;i++)
54         {
55             edge[i].data=i;
56             edge[i].a.clear();
57         }
58         int start;
59         for(i=1;i<=n;i++)
60         {
61 //            cin>>j;
62 //            cin>>c;
63 //            cin>>c;
64 //            cin>>k;
65 //            cin>>c;
66             scanf("%d:(%d)",&j,&k);
67             if(i==1) start=j;
68             for(s=1;s<=k;s++)
69             {
70 //                cin>>t;
71                 scanf("%d",&t);
72                 
73                 edge[j].a.push_back(t);
74 //                edge[t].a.push_back(j);
75                 
76             }
77         }
78         memset(v,0,sizeof(v));
79         cout<<solve(start)<<endl;
80     }
81 }
82 
83 int main(){
84     read();
85     return 0;
86 }

posted on 2012-08-10 21:13  矮人狙击手!  阅读(433)  评论(0编辑  收藏  举报

导航