1 条题解
-
0
C++ :
//此题是一个典型的树归,因为可能多门课程共用同一个先决课程,所以这是一颗普通树 //同时有些科目可能没有先决课程,这样就可能是一个森林,一个森林是没法用树归的, //那我们可以让不同的子树以0为根节点,形成一颗树,其中0为虚根,其学分为零,这样 //这样我可以枚举以0点为根的子树,选n门课时的最大值,但是这样做需要枚举根的每一个 //儿子,而且不同根,它的儿子树也不相同,所以做起来比较复杂,我们在学习树形结构时 //掌握了普通树转二叉树的方法,原则是左儿子保留不变,兄弟变右儿子,这样转了后我们 //设f[i][j]表示以i节点为根,选j门课程的最大学分,那么,对i的左儿子来说i是必选课程, //而右儿子是i的兄弟,没有必选的关系,所以选择根i节点的话,那么可以对左子树选k门 //右儿子选j-k-1门,要么就是只选右子树。 //f[i][j]=max{f[i_right][j],f[i_left][k]+f[i_right][j-k-1]+a[i]} #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=1001; struct tre { int lc,rc; }; int m,n,f[maxn][maxn]={0},a[maxn]; tre tree[maxn]; void init(); int my_max(int,int); void insert(int,int); int dp(int,int); int main() { init(); cout<<dp(tree[0].lc,n)<<endl;//根0为虚根,所以其没有右子树,结果从其左子树找n门课程 return 0; } void init() { memset(tree,0,sizeof(tree)); cin>>m>>n; for(int i=1;i<=m;i++) { int fa;//fa为i的直接必选课程 cin>>fa>>a[i]; insert(i,fa);//建树 } } void insert(int son,int father) { if(!tree[father].lc)//如果父亲节点没有左儿子则,该点为其左儿子 { tree[father].lc=son; } else//如果有左儿子,则成为相邻兄弟的右儿子 { int t=tree[father].lc; while(tree[t].rc) t=tree[t].rc;//递归找到第一个没有右儿子的节点 tree[t].rc=son; } } int dp(int x,int y) { if(f[x][y]>0)return f[x][y];//如果有值则返回 if(x==0||y==0)//x==0表明该节点没有子树,y为0表明不选任何课程 { f[x][y]=0; return f[x][y]; } f[x][y]=dp(tree[x].rc,y);//先假设不选根x节点,则只选其右子树 for(int i=0;i<=y-1;i++)//如果选根x节点,左儿子选i个节点,i从[0,y-1] { f[x][y]=my_max(f[x][y],dp(tree[x].lc,i)+dp(tree[x].rc,y-i-1)+a[x]); } return f[x][y]; } int my_max(int x,int y) { return x>y ? x:y; }
Pascal :
var i,j,n,m,w:longint; ans,f:Array[-1..200,-1..200] of longint; k,s,le,ri:Array[0..200] of longint; function max(a,b:longint):longint; begin if a>b then exit(a) else exit(b); end; procedure work(num:longint); var i,j:longint; begin if num=-1 then exit; if (le[num]=-1) and (ri[num]=-1) then begin for i:=1 to m do ans[num,i]:=s[num]; exit; end; work(le[num]); work(ri[num]); for i:=1 to m do begin ans[num,i]:=max(ans[num,i],ans[ri[num],i]); end; if num=0 then exit; for i:=0 to m-1 do for j:=0 to i do ans[num,i+1]:=max(ans[num,i+1],ans[le[num],j]+ans[ri[num],i-j]+s[num]); end; begin readln(n,m); for i:=1 to n do begin read(k[i],s[i]); inc(f[k[i],0]); f[k[i],f[k[i],0]]:=i; end; for i:=0 to n do begin le[i]:=-1; ri[i]:=-1; end; for i:=0 to n do if f[i,0]<>0 then begin le[i]:=f[i,1]; w:=f[i,1]; for j:=2 to f[i,0] do begin ri[w]:=f[i,j]; w:=f[i,j]; end; end; //write(le[0]); work(0); write(ans[le[0],m]); // for i:=0 to m do // begin // f[0,m]:=max(f[0,m],f[le[0],i]+f[ri[0],m-i]); // write(f[0,m],' '); // end; // write(f[le[0],m]); end.
- 1
信息
- ID
- 841
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者