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 }
多叉转二叉,左孩子右兄弟。
若选根结点,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 ",f[ch[n+1]][m]); 58 path(ch[n+1],m); 59 rep(i,1,n) if(ans[i]) printf("%d ",i); 60 return 0; 61 }