习题选讲

70
习习习习 习习习 [email protected]

description

习题选讲. 赵浩泉 [email protected]. 动态规划. Pick numbers The Top-Code 过河 The Longest Walk Hie with the Pie 电子眼 Fight Club GECKO 能量项链 Antimonotonicity Missile Bridging Signals. 动态规划. Counting Problem HOUSING Circular Sequence Apple Tree Maximum Sum 金明的预算方案 运动会 Cash Machine 开心的金明 - PowerPoint PPT Presentation

Transcript of 习题选讲

Page 1: 习题选讲

习题选讲

赵浩泉[email protected]

Page 2: 习题选讲

2 2011-12-21

动态规划 Pick numbers The Top-Code 过河 The Longest Walk Hie with the Pie 电子眼 Fight Club GECKO 能量项链 Antimonotonicity Missile Bridging Signals

Page 3: 习题选讲

3 2011-12-21

动态规划 Counting Problem HOUSING Circular Sequence Apple Tree Maximum Sum 金明的预算方案 运动会 Cash Machine 开心的金明 Knapsack Dairy Queen

Page 4: 习题选讲

4 2011-12-21

Pick numbers题目大意:给一个M*N的格子,现在需要从左上角走到右下角,并且只能往下或往右走,并且要把走过的格子中的数加起来,现在要求和为正并且越小越好,求和。

2<=M,N<=10,格子中的数范围为 [-10,10]

Page 5: 习题选讲

5 2011-12-21

Pick numbers解题思路:因为只能往下和往右走,因此走第二行的格子必定在走第一行的格子之后,在同一行里,靠左的格子必定先走。

从左上角到右下角总共经过 M+N-1个格子,因此得到的和的范围为 [-190,190]。

Page 6: 习题选讲

6 2011-12-21

Pick numbers使用动态规划,按走的顺序记录到达每个格子可能出现的所有的和。

每个格子使用一个数组,如果某个和可能出现,则这个位置标为 true。

每个格子可能出现的和,只可能从它的左方或上方格子可能出现的和,加上当前格子的值得到。

Page 7: 习题选讲

7 2011-12-21

Pick numbers mid=200; ans=-1; dp[1][1][mid+a[1][1]]=true; for (i=1;i<=m;i++) for (j=1;j<=n;j++) if (i!=1||j!=1) for (k=0;k<=mid+mid;k++) { if (dp[i-1][j][k]) dp[i][j][k+a[i][j]]=true; if (dp[i][j-1][k]) dp[i][j][k+a[i][j]]=true; } for (k=mid+1;k<=mid+mid;k++) if (dp[m][n][k]) { ans=k-mid; break; }

Page 8: 习题选讲

8 2011-12-21

The Top-Code

题目大意:给出一个字符串,要求把它切成长度不小于 2的几段,使得每一段的字典序比它前一段的字典序小,求最大能切成的段数,在当前段数下的方案数,在当前段数下字典序最小的方案。

字符串长度不超过 100。

Page 9: 习题选讲

9 2011-12-21

The Top-Code

解题思路: 动态规划。每次要切新的一段,能切出的字符串只决定于上一个切出来的字符串。

状态 dp[i][j], i表示上一个字符串起始位置, j表示当前字符串起始位置。状态转移时,枚举当前字符串长度,并与上一个字符串长度逐个比较,确定是否能转移。

转移过程中更新最多段数,和到达最多段数的方法数,并把所有可行转移边记录下来。

寻找字典序最小方案时,从结束状态开始,沿着转移边反向寻找到所有可能经过的状态,再从起始状态开始,只沿可能经过的状态贪心转移,最终到达结束状态。

http://222.200.182.58/viewsource.php?sid=1095986

Page 10: 习题选讲

10 2011-12-21

过河题目大意:桥的起点为 0,终点为 L,其中地有M个石子。青蛙每次跳的范围为 [S,T],问要跳过桥最小踩到石子次数。

1 <= L <= 10^9 1 <= S <= T <= 10 1 <= M <= 100

Page 11: 习题选讲

11 2011-12-21

过河 解题思路: L的值大太,直接按 L的值进行动态规划不可行。

分情况:若 S和 T相等,则踩到的石子数是固定的;

若 S和 T不相等,因为 S和 T的最大值为 10,所以当两个石子相差太远是没有意义的,这里取的值为 90,当石子距离相差 90以上时,看作90,答案不变。

压缩后桥长度不超过 10000,直接动态规划即可。

Page 12: 习题选讲

12 2011-12-21

过河 for(i=0;i<m;i++) { delta[i]=rock[i+1]-rock[i]; if(delta[i]>90)delta[i]=90; } for(i=1;i<=m;i++) rock[i]=rock[i-1]+delta[i-1]; for(i=1;i<=m;i++) dp[rock[i]]=1; f[0]=1; work();

Page 13: 习题选讲

13 2011-12-21

过河 void work() { L=rock[m]+90; for(i=s;i<=L;i++) { max=101; for(j=i-t;j<=i-s;j++) if(j>=0) if(f[j]&&dp[j]+dp[i]<max) { max=dp[j]+dp[i]; f[i]=1; } dp[i]=max; } }

Page 14: 习题选讲

14 2011-12-21

The Longest Walk

题目大意:给出一个图,求出不经过重复点最长路径。

隐藏条件:图的点数不超过 12。

Page 15: 习题选讲

15 2011-12-21

The Longest Walk

解题思路: 动态规划,状态为已经经过哪些点,当前所在位置。

状态转移,在当前状态可以到达哪个没有到达过的点,到达新的状态,并纪录转移。

输出路径时,从结束结点开始,按照纪录的转移倒推输出。

如果状态转移是倒推的,则输出的结果不需再倒推。

Page 16: 习题选讲

16 2011-12-21

The Longest Walk

for(i=1;i<20;i++) t[i]=t[i-1]*2; for(i=1;i<t[n];i++)for(j=0;j<n;j++){ if((i&t[j])==0) continue; for(k=0;k<n;k++){ if(j==k||(i&t[k])==0) continue; if(b[j][k]&&a[j][i]<b[j][k]+a[k][i-t[j]]){ a[j][i]=b[j][k]+a[k][i-t[j]]; suc[j][i]=k; } } }

Page 17: 习题选讲

17 2011-12-21

Hie with the Pie

题目大意:给出一个图,求出从起点经过所有点并回到起点的最短路径,可以经过重复点。

点数不超过 10。

Page 18: 习题选讲

18 2011-12-21

Hie with the Pie

解题思路: 动态规划,状态为已经经过哪些点,当前所在位置。

状态转移,在当前状态可以到达哪个没有到达过的点,到达新的状态,并纪录转移。

因为可以经过重复点,先调用 floyd算法求出所有点之间的最短路。

Page 19: 习题选讲

19 2011-12-21

Hie with the Pie for(int state=opt[0][1<<0]=0;state<(1<<n);state++) for(i=0;i<n;i++) if((state&(1<<i))&&opt[i][state]!=-1) { for(j=0;j<n;j++) { int newstate=state|(1<<j); if(opt[j][newstate]==-1 ||opt[j][newstate]>opt[i][state]+g[i][j]) opt[j][newstate]=opt[i][state]+g[i][j]; } } int ans=opt[0][(1<<n)-1];

Page 20: 习题选讲

20 2011-12-21

电子眼题目大意:一个城市有 N条马路和 N个路口,在路口安装一个电子眼可以监视和它连接的马路,问最小需要多少电子眼才可以监视所有马路。

1<=N<=100000

Page 21: 习题选讲

21 2011-12-21

电子眼 解题思路: N个结点 N-1条边的连通图是树,则 N个结点 N条边的连通图只存在一个环。

假设题目所求的图是树,则可以用树型动态规划解决:从一个结点开始,当前结点包括的状态是,如果子结点连向它的边全部已经被监视需要的电子眼数,和存在还没被监视的边需要的电子眼数,则可先递归算出子结点的信息,在转移时,如果存在边还没被监视,则当前结点必须安装,否则可以安装也可以不安装,取最小值。

当图存在一个环的时候,可以找到环中的一条边,分别假设这条边的其中一个结点是否安装电子眼,并分别求解。

Page 22: 习题选讲

22 2011-12-21

电子眼 void dfs(long k,long &x1,long &y1,long &x2,long &y2) { long temp,nextx1,nexty1,nextx2,nexty2; x1=x2=0; y1=y2=1; for (node* pp=b[k];pp!=NULL;pp=pp->next) { temp=pp->xx; if ((temp==p&&k==q)||(temp==q&&k==p)); else if (d[temp]==0) { d[temp]=1; dfs(temp,nextx1,nexty1,nextx2,nexty2); x1+=nexty1; x2+=nexty2; if (nextx1<nexty1) y1+=nextx1; else y1+=nexty1; if (nextx2<nexty2) y2+=nextx2; else y2+=nexty2; } } if (k==q) x1=y2=1000000; }

Page 23: 习题选讲

23 2011-12-21

Fight Club

题目大意: N个人站成一圈,每个人都只能与相邻的人战斗,输的人离开这个圈,直到圈里只剩下一个人。给出每两个人之间的战斗胜负关系表,求出每个人是否能成为圈里剩下的唯一一个人。

Page 24: 习题选讲

24 2011-12-21

Fight Club 解题思路: 要成为圈中唯一剩下的人,则其他人全部都要打败,而每个人只能与旁边的人战斗,因此对于每个状态下每个人只关心两边的人。

动态规划,状态为区间 [i,j],表示从第 i个人逆时针方向数到第 j个人之间所有人(不包括 i和 j)都已经被打败。

状态转移,每个区间 [i,j]能够达到,则需要在 i和 j之间存在一个人 k,使得 [i,k]能够成立,且 [k,j]能够成立,且 k会被 i和 j其中一个人打败。

初始时长度为 0的区间必定成立,且长度较大的区间需要长度较小的区间得到,因此枚举顺序为区间的长度从小到大。

最后对于每个人 i,如果 [i,i]成立,则表示所有其它人都被打败。

Page 25: 习题选讲

25 2011-12-21

Fight Club memset(f, 0, sizeof(f)); for (int i=0; i<n; i++) f[i][(i+1)%n] = 1; for (int d=2; d<=n; d++) for (int i=0; i<n; i++) { int j = (i+d)%n; for (int k=(i+1)%n; k!=j; k=(k+1)%n) if (f[i][k] && f[k][j] && (a[i][k] || a[j][k])) { f[i][j] = 1; break; } }

Page 26: 习题选讲

26 2011-12-21

GECKO

题目大意: 一只壁虎在墙上的格子爬,每个格子上有不同数量的蚊子。壁虎只能从第一行格子开始,每一次爬动都只能爬到下一行格子,只能爬到它所在格子的下一行位置或旁边位置的格子。它每到达一个格子就把格子中的蚊子吃了。问最多能吃的蚊子数量。

格子的行数和列数不超过 500。

Page 27: 习题选讲

27 2011-12-21

GECKO

解题思路: 动态规划,状态为一个格子,如果壁虎现在在这个格子里,它最多已经吃了的蚊子数量。

状态转移,对于每一个格子,都只能从上一行的三个格子转移过来,取其中的最大值即可。

按行的顺序枚举。

Page 28: 习题选讲

28 2011-12-21

GECKO

for (i=1;i<h;i++) { a[i][0]+=max(a[i-1][0],a[i-1][1]); for (j=1;j<w-1;j++) a[i][j]+=max(a[i-1][j-1],a[i-1][j],a[i-1][j+1]); a[i][w-1]+=max(a[i-1][w-1],a[i-1][w-2]); }

Page 29: 习题选讲

29 2011-12-21

能量项链题目大意:给出一串项链,每次可以选相邻两个珠子进行聚合,释放出一定的能量,并产生一个新珠子。项链是头尾相接的。求释放的能量的总和的最大值。

项链长度不超过 100。

Page 30: 习题选讲

30 2011-12-21

能量项链 解题思路: 每次聚合,都会使数字中一的个数字消失。 动态规划,状态为 [i,j]表示从 i开始,按顺时针方向到 j,这一段珠子所聚合得到的能量最大值。

状态转移,要求出 [i,j]的值,则存在一个 k在 i和 j之间, [i,j]的值为 [i,k]的值与 [k+1,j]的值与这次聚合所释放出的能量的总和,取最大值。

且长度较大的区间需要长度较小的区间得到,因此枚举顺序为区间的长度从小到大。

Page 31: 习题选讲

31 2011-12-21

能量项链 for (step=1;step<n;step++) for (i=0;i<n*2;i++) { j=i+step; if (j>=n*2) break; for (k=i;k<j;k++) temp=ans[i][k]+ans[k+1][j]+a[i]*a[k+1]*a[j+1]; if (ans[i][j]<temp) ans[i][j]=temp; }

Page 32: 习题选讲

32 2011-12-21

Antimonotonicity Missile

题目大意:给出一列数,现在要找出最长的子序列,满足第一个数大于第二个数,第二数小于第三个数,第三个数大于第四个数,如此类推。

Page 33: 习题选讲

33 2011-12-21

Antimonotonicity Missile

解题思路: 动态规划,状态为在当前的数字,最长的子序列长度。

状态转移,若在原数列中,当前数字比上一个数字小,若子序列长度为奇数,则可加上当前数字,若子序列长度为偶数,则可用当前数字替换上一个数字,长度不变;若当前数字比上一个数字大,也可同理。

Page 34: 习题选讲

34 2011-12-21

Antimonotonicity Missile

l=1; for (i=2;i<=n;i++) { if (a[i]<a[i-1]&&l%2==1) l++; else if (a[i]>a[i-1]&&l%2==0) l++; }

Page 35: 习题选讲

35 2011-12-21

Bridging Signals

题目大意:左边有一列 p个数,右边有一列 p个数,并给出它们之间的连线情况,问最多可以保留多少个连线,使到中间的连线不会出现交叉。

P<40000

Page 36: 习题选讲

36 2011-12-21

Bridging Signals 解题思路: 要求最大的不交叉连线数量,问题等价于求最长上升子序列。

最长上升子序列动态规划解法: 状态,以当前数字为子序列的最后一个数,则子序列的最大长度;

状态转移,对每个数字,找出在这个数字之前出现并且比它小的所有数字,并且从其中找出长度最大的数,加上一即是当前数字的最大子串长度。

D[i]=max{1,D[j]+1} j=1,2,...,i-1 并且 A[i]>A[j] 复杂度 O(N^2)

通过以上解法可以改进成 O(NlogN)的。按数字大小建立线段树,那么在线段树上的操作只有插入一个数和查找某个区间的最大值,可以实现。

Page 37: 习题选讲

37 2011-12-21

Bridging Signals 最长上升子序列的其它解法: 维护一个一维数组,数组里的第 i个数表示最长上升子序列长度是 i的所有子序列中末尾最小的那个数。因此这个数组是递增的。按顺序插入每一个数的时候,在数组中找到比它大的最小的数,并更新这个位置;如果它比所有数都大,增数组长度增加一,并把它放在最末端。寻找的时候使用二分查找。

最后的最大长度等于数组长度。复杂度 O(NlogN) 例如,原序列为 1 , 5 , 8 , 3 , 6 , 7 数组为 1 , 5 , 8 ,此时读到 3 ,用 3 替换 5 ,得到 1 ,

3 , 8 ; 再读 6 ,用 6 替换 8 ,得到 1 , 3 , 6 ;再读7 ,得到最终数组为 1 , 3 , 6 , 7 。最长递增子序列为长度 4 。

Page 38: 习题选讲

38 2011-12-21

Bridging Signals nn=0;c[0]=0; for (i=1;i<=n;i++) { if (a[i]>c[nn]) { c[++nn]=a[i]; b[i]=nn; } else { hi=upper_bound(c,c+nn+1,a[i])-c; c[hi]=a[i]; b[i]=hi; } }

Page 39: 习题选讲

39 2011-12-21

Counting Problem

题目大意: 一个 N*N的棋盘,在里面放棋子,使得每行有且只有两个棋子,每列有且只有两个棋子,问有多少种方法。通过交换两行或交换两列的方法得到相同的棋盘看作同一种。

N<=500

Page 40: 习题选讲

40 2011-12-21

Counting Problem

解题思路:问题可转化为把 N分解成大于 2的整数之和有多少种分法。

动态规划,状态 a[i][j]表示把 i分解成大于j的整数之和有多少种分法。

状态转移, a[i][j]=sum(a[i-k][k])(k>=j)。

Page 41: 习题选讲

41 2011-12-21

Counting Problem for (i=0;i<=500;i++) { for (j=0;j<=500;j++) { if (i==0) a[i][j]=1; else if (i<j) a[i][j]=0; else { a[i][j]=0; for (k=max(2,j);k<=i;k++) a[i][j]=(a[i][j]+a[i-k][k])

%1000007; } } ans[i]=a[i][2]; }

Page 42: 习题选讲

42 2011-12-21

HOUSING

题目大意: N个人分到屋里,每间房至少 5个人,有多少种分法?

5 <= n <= 100

Page 43: 习题选讲

43 2011-12-21

HOUSING

解题思路:问题可转化为把 N分解成大于 5的整数之和有多少种分法。

和上题一样。

Page 44: 习题选讲

44 2011-12-21

HOUSING for (i=0;i<=100;i++) { for (j=0;j<=100;j++) { if (i==0) a[i][j]=1; else if (i<j) a[i][j]=0; else { a[i][j]=0; for (k=max(5,j);k<=i;k++) a[i][j]=a[i][j]+a[i-k][k]; } } ans[i]=a[i][5]; }

Page 45: 习题选讲

45 2011-12-21

Circular Sequence

题目大意:有一个长度为 n的循环队列,求出一个和最大的连续子串。

1<=n<=100000

Page 46: 习题选讲

46 2011-12-21

Circular Sequence 解题思路: 首先判断序列中是否全部都是负数,如果是的话,最大和即为最大的负数。

如果序列并不是循环的,有已知的 O(n)方法求出最大值。

int cal() { int answer=0,sum=0; for (int i=0;i<n;i++) { sum+=i; if (sum>ans) ans=sum; if (sum<0) sum=0; }

Page 47: 习题选讲

47 2011-12-21

Circular Sequence

则求循环队列的最大值,可以当作不循环队列,可能是最大和,也可能是总和减去最小和。

sum1=cal(); for (i=0;i<n;i++) { sum+=a[i]; a[i]=-a[i]; } sum2=sum+cal(); return max(sum1,sum2);

Page 48: 习题选讲

48 2011-12-21

Apple Tree

题目大意:有一棵苹果树有 N个结点,每个结点上有苹果,最多可以沿着苹果树的边走 K步,每走过一个结点把上面的苹果吃掉。问最多可以吃多少个苹果。

1<=N<=100, 0<=K<=200

Page 49: 习题选讲

49 2011-12-21

Apple Tree

解题思路: 使用树型动态规划,每个结点的状态为,以这个结点为根的子树上使用不同步数,并且是否会回来原结点,所吃的苹果的最大值。

状态转移,每个结点,对于每个子结点,可以枚举分配多少步数到这个子结点上。

http://222.200.182.58/viewsource.php?sid=102025

Page 50: 习题选讲

50 2011-12-21

Maximum Sum

题目大意:有一个数列,求出两个连续的子序列,使得它们的和最大。

Page 51: 习题选讲

51 2011-12-21

Maximum Sum

解题思路:现在已知求一列数的一个连续子序列最大和的方法,因此可以求出从左边数起的任意一个子段的连续子序列最大和,再求出从右边数起的,再枚举中间切开数列的位置,把左右两部分加起来,即可得到答案。

Page 52: 习题选讲

52 2011-12-21

Maximum Sum sum=ans=0; for (i=0;i<n;i++) { sum+=a[i]; if (sum>ans) ans=sum; if (sum<0) sum=0; s1[i]=ans; } sum=ans=0; for (i=n-1;i>=0;i--) { sum+=a[i]; if (sum>ans) ans=sum; if (sum<0) sum=0; s2[i]=ans; }

Page 53: 习题选讲

53 2011-12-21

Maximum Sum

ans=0; for (i=1;i<n;i++) if (s1[i-1]+s2[i]>ans) ans=s1[i-1]+s2[i];

Page 54: 习题选讲

54 2011-12-21

Knapsack

题目大意:给出背包的容量,给出各种物品大小,求在不超过背包容量情况下的最大占用体积。

Page 55: 习题选讲

55 2011-12-21

Knapsack 解题思路: 0-1背包问题裸题。scanf("%d%d", &n, &m);for (int i=0; i<n; i++) scanf("%d", w+i);

//dpfill(f, f+m+1, 0);f[0] = 1;for (int i=0; i<n; i++) for (int j=m-w[i]; j>=0; j--) if (f[j]) f[j+w[i]] = 1; int ans;for (ans = m; !f[ans]; ans--);

Page 56: 习题选讲

56 2011-12-21

开心的金明 题目大意: 金明想买一些物品(不超过M件),第 j件物品的价格为 v[j],重要度为 w[j].他希望在不超过 N元(可以等于 N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

请你帮助金明设计一个满足要求的购物单。

Page 57: 习题选讲

57 2011-12-21

开心的金明解题思路:这题是 0-1背包问题。

Page 58: 习题选讲

58 2011-12-21

开心的金明while (cin>>n>>m){

//readfor (int i=1; i<=m; i++) cin>>v[i]>>p[i];

//initializefor (int j=0; j<=m; j++) f[0][j]=0;for (int i=0; i<=n; i++) f[i][0]=0;//dpfor (int i=1; i<=n; i++) { for (int j=1; j<=m; j++) { if (i-v[j]>=0) {

f[i][j]=max(f[i][j-1], f[i-v[j]][j-1]+v[j]*p[j]);

} else { f[i][j]=f[i][j-1]; } }}//outputcout<<f[n][m]<<endl;

}

Page 59: 习题选讲

59 2011-12-21

运动会题目大意:一个人去参加运动会,一天最多参加一个项目,并且参加的项目消耗的精力总和不能超过他的总精力,赢得的项目有奖金。求最大的奖金数量。

Page 60: 习题选讲

60 2011-12-21

运动会解题思路:分组背包,对每一天,选项为可以参加任意一场比赛,也可以不参加比赛。

Page 61: 习题选讲

61 2011-12-21

运动会 memset(a,0,sizeof(a)); i=k=0; while (k<n) { if (i<d[k]) i++; for (j=0;j<=p;j++) { if (i<d[k]) a[i+1][j]=a[i][j]; else { a[i+1][j]=max(a[i][j],a[i+1][j]); if (j+e[k]<=p&&a[i][j]+m[k]>a[i+1][j+e[k]]) a[i+1][j+e[k]]=a[i][j]+m[k]; } } if (i>=d[k]) k++; }

Page 62: 习题选讲

62 2011-12-21

Cash Machine

题目大意:一台机器里有 N种纸币,每种纸币有不同的面额和对应的数量。再给出一个额度,问不超过这个额度能得到最大的数量是多少。

Page 63: 习题选讲

63 2011-12-21

Cash Machine

解题思路:使用动态规划,状态为当前金额是否能取到,并且最后是通过拿多少张何种面额的纸币得到。

状态转移,如果某状态在当前面额的纸币上没有拿完,则可以继续拿,并对相应的金额更新答案。

Page 64: 习题选讲

64 2011-12-21

Cash Machine //input scanf("%d", &n); for (int i=0; i<n; i++) scanf("%d %d", a+i, b+i); //dp memset(f, 0, sizeof(f)); f[0] = 1; for (int i=0; !f[m] && i<n; i++) for (int j=m; !f[m] && j>=0; j--) if (f[j]) { for (int k=1; k<=a[i]; k++) { int x = j+k*b[i]; if (x>m || f[x]) break; f[x] = 1; } } //output while (!f[m] && m>0) m--; printf("%d\n", m);

Page 65: 习题选讲

65 2011-12-21

Dairy Queen

题目大意:给出一些硬币的面额,不限数量,给出一个金额,问组成的方法数有多少种。

Page 66: 习题选讲

66 2011-12-21

Dairy Queen 解题思路: 对每种硬币,若面额为 C,并且在这之前能构成金额 j(包括 C),则加上这种硬币能构成金额 j+C,即 j的方案数累加到 j+C上。 int i, j;

memset(dp, 0, sizeof(dp)); dp[0] = 1; for (i = 0; i < c; i++) { int t = c_i[i]; for (j = 1; j <= n; j++) { if (t <= j) dp[j] += dp[j - t]; } } // answer is dp[n];

Page 67: 习题选讲

67 2011-12-21

金明的预算方案题目大意:金明想买东西,但价格不能超过 N。物件分成主件和附件,要先买了主件才能买附件。每个物品有重要度,现在所买的物品的价格与重要度的乘积的和最大。

每个主件最多有两个附件。

Page 68: 习题选讲

68 2011-12-21

金明的预算方案解题思路:这题是变种的 0-1背包问题。把每个主件看作一个物体,而取的方法包括 {不取,只取主件,取主件和附件 1,取主件和附件2,取主件和两个附件 },然后用解决背包问题的方法解决。

Page 69: 习题选讲

69 2011-12-21

金明的预算方案 for (i=1;i<=m;i++) { if (q[i]!=0) { for (j=0;j<=n;j++) b[j][i]=b[j][i-1]; } else { for (j=0;j<=n;j++) { b[j][i]=b[j][i-1]; for (k=0;k<4;k++) { if (j>=c[k][i]&&a[k][i]+b[j-c[k][i]][i-1]>b[j][i]) b[j][i]=a[k][i]+b[ j-c[k][i] ][i-1]; } } } }

Page 70: 习题选讲

70 2011-12-21

谢谢!