cogs 1199选课(树形dp 背包或多叉转二叉

http://cogs.pro:8080/cogs/problem/problem.php?pid=vQyiJkkPP

题意:给m门课,每门课在上完其先修课后才能上,要你从中选n门课使得总学分尽可能大。

思路:背包,没有先修课看成其先修课编号为0,求一个f[0][n]的背包,表示以0为根的树选n个结点的最大总权值,设x为根,y为x的孩子,对每个孩子,dfs(y),然后f[[x][t]=max(f[x][t],f[x][t-j]+f[y][j])用每个孩子更新x,最后若x不是0,再用自己的权值更新自己。但背包好像不能记录路径。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,b) for(int i=a;i<=b;++i)
 3 #define dep(i,a,b) for(int i=a;i>=b;--i)
 4 using namespace std;
 5 const int MAXN=310;
 6 int read(){
 7     int sum=0,flag=1;
 8     char c;
 9     for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
10     for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
11     return sum*flag;
12 }
13 int n,m;
14 int v[MAXN];
15 vector<int>son[MAXN];
16 int f[MAXN][MAXN];
17 void init(){
18     n=read();m=read();
19     rep(i,1,n){
20         int y;
21         y=read();v[i]=read();
22         son[y].push_back(i);
23     }
24 }
25 void DP(int x){
26     f[x][0]=0;
27     for(int i=0;i<son[x].size();++i){
28         int y=son[x][i];
29         DP(y);
30         dep(t,m,0)
31             dep(j,t,0)
32                 if(t>=j)
33                     f[x][t]=max(f[x][t],f[x][t-j]+f[y][j]);
34     }
35     if(x!=0) dep(t,m,1) f[x][t]=f[x][t-1]+v[x];
36 }
37 int main(){
38     init();
39     DP(0);
40     printf("%d",f[0][m]);
41     return 0;
42 }
View Code

 

多叉转二叉,左孩子右兄弟。

若选根结点,f[i][j] = f[br[i][j]

若不选根结点,f[i][j] = f[ch[i]][k]+f[br[i]][j-1-k]+v[i]

递归寻找路径方法类似。

 1 #include<bits/stdc++.h>
 2 #define rep(i,a,b) for(int i=a;i<=b;++i)
 3 #define dep(i,a,b) for(int i=a;i>=b;--i)
 4 using namespace std;
 5 const int MAXN=510;
 6 int read(){
 7     int sum=0,flag=1;
 8     char c;
 9     for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
10     for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
11     return sum*flag;
12 }
13 int n,m;
14 int v[MAXN];
15 int br[MAXN],ch[MAXN];
16 bool ans[MAXN];
17 int f[MAXN][MAXN];
18 void init(){
19     n=read();m=read();
20     int x;
21     rep(i,1,n){
22         x=read();
23         v[i]=read();
24         if(!x) x=n+1;
25         br[i]=ch[x];
26         ch[x]=i;
27     }
28     memset(f,-1,sizeof f);
29 }
30 void DP(int x,int y){
31     if(f[x][y]>=0) return;
32     if(!x||!y) {f[x][y]=0;return;}
33     DP(br[x],y);
34     rep(i,0,y-1){
35         DP(br[x],i);
36         DP(ch[x],y-i-1);
37         f[x][y]=max(f[x][y],max(f[br[x]][y],f[br[x]][i]+f[ch[x]][y-i-1]+v[x]));
38     }
39 }
40 void path(int x,int y){
41     if(!x||!y) return;
42     if(f[x][y]==f[br[x]][y]) path(br[x],y);
43     else {
44         rep(i,0,y-1){
45             if(f[x][y]==f[br[x]][i]+f[ch[x]][y-i-1]+v[x]){
46                 path(br[x],i);
47                 path(ch[x],y-i-1);
48                 ans[x]=1;
49                 return;
50             }
51         }
52     }
53 }
54 int main(){
55     init();
56     DP(ch[n+1],m);
57     printf("%d\n",f[ch[n+1]][m]);
58     path(ch[n+1],m);
59     rep(i,1,n) if(ans[i]) printf("%d\n",i);
60     return 0;
61 }
View Code

 

posted @ 2019-08-22 14:04  时光已随风而逝~  阅读(176)  评论(0编辑  收藏  举报