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 }