标签:des style blog http color java 使用 os
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2371 Accepted Submission(s): 1079
3 1 1 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1
dp[pos][num]表示以pos为根节点的子树下,用去num个机器人,所得到的最小值
特别的是当num==0的时候,dp[pos][0]表示用一个机器人去走完所有子树,最后又回到pos这个节点
状态转移:dp[pos][num]=min∑{dp[pos_j][num_j]+w_j},pos_j是pos的所有儿子,
当num_j==0的时候,和别的时候不同,特别处理一下就好。
状态转移并不难,最精华的,我不认为是状态转移,而是转移时使用的那个“分组背包”思想。
使用一维数组的“分组背包”伪代码如下:
for 所有的组i
for v=V..0
for 所有的k属于组i
f[v]=max{f[v],f[v-c[k]]+w[k]}
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 struct Edge{ 8 int to; 9 int value; 10 int next; 11 }edge[2*10008]; 12 int head[10008],dp[10008][12]; 13 int N,S,K,total; 14 15 inline int MIN(int a,int b) 16 { 17 if(a<b) return a; 18 return b; 19 } 20 void addEdge(int start,int end,int value) 21 { 22 edge[total].to=end;edge[total].value=value; 23 edge[total].next=head[start];head[start]=total++; 24 25 edge[total].to=start,edge[total].value=value; 26 edge[total].next=head[end],head[end]=total++; 27 } 28 29 void DP(int source,int pre) 30 { 31 for(int i=head[source];i!=-1;i=edge[i].next) 32 { 33 int to=edge[i].to; 34 if(to==pre) continue; 35 DP(to,source); 36 for(int j=K;j>=0;j--) 37 { 38 dp[source][j]+=dp[to][0]+2*edge[i].value; 39 for(int k=1;k<=j;k++) 40 dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value); 41 } 42 } 43 } 44 45 int main() 46 { 47 while(scanf("%d %d %d",&N,&S,&K)!=EOF) 48 { 49 memset(dp,0,sizeof(dp)); 50 memset(head,-1,sizeof(head)); 51 total=0; 52 53 int x,y,cost; 54 for(int i=1;i<N;i++) 55 { 56 scanf("%d %d %d",&x,&y,&cost); 57 addEdge(x,y,cost); 58 } 59 DP(S,-1); 60 printf("%d\n",dp[S][K]); 61 } 62 return 0; 63 }
思路和其他人差不多,谈谈自己是怎么理解的吧:
首先,用两数组建立无向树,还是第一次,费了不少功夫。定义一个结构代表边edge[i]={to,next,value},其中edge[i]表示第i条边,to是边的末点,value就不说了,next代表的是同一父节点边方向相同的与此边相邻的左边的边的编号,其中最左是-1。以此为基础建立一个边数组(注意数组大小是顶点数的两倍),还有用一个head[i]数组来表示最右边的边的编号。
解释这一段代码,当时写的理解的不是很好:
1 void DP(int source,int pre) 2 { 3 for(int i=head[source];i!=-1;i=edge[i].next) 4 { 5 int to=edge[i].to; 6 if(to==pre) continue; 7 DP(to,source); 8 for(int j=K;j>=0;j--) 9 { 10 dp[source][j]+=dp[to][0]+2*edge[i].value; 11 for(int k=1;k<=j;k++) 12 dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value); 13 } 14 } 15 }
第一层for循环查找与节点source相连的各条边,to是此边对应的末点,若此边是叶子节点则to==pre(由于节点最左边的边访问完以后,只有到他父节点的边,这里只能用continue,因为不确定访问的顺序,return不合适),递归访问子节点此时应用01背包,由于dp[source][0]比较特殊单独处理,一棵子树对应一个分组,dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);也比较好理解。
树形DP-----HDU4003 Find Metal Mineral,布布扣,bubuko.com
树形DP-----HDU4003 Find Metal Mineral
标签:des style blog http color java 使用 os
原文地址:http://www.cnblogs.com/Chinahenu/p/3914358.html