DP专题
- 多阶段决策:递推——逆推方式(难度较大),记忆化搜索方式,考虑当前决策层(cur)
- 01背包:变形众多,两种方式,一是考虑阶段的方式, ,另一种是刷表法
题目推荐:
bzoj 4247
Description
JOI君有N个装在手机上的挂饰,编号为1...N。 JOI君可以将其中的一些装在手机上。
JOI君的挂饰有一些与众不同——其中的一些挂饰附有可以挂其他挂件的挂钩。每个挂件要么直接挂在手机上,要么挂在其他挂件的挂钩上。直接挂在手机上的挂件最多有1个。
此外,每个挂件有一个安装时会获得的喜悦值,用一个整数来表示。如果JOI君很讨厌某个挂饰,那么这个挂饰的喜悦值就是一个负数。
JOI君想要最大化所有挂饰的喜悦值之和。注意不必要将所有的挂钩都挂上挂饰,而且一个都不挂也是可以的。
Input
第一行一个整数N,代表挂饰的个数。
接下来N行,第i行(1<=i<=N)有两个空格分隔的整数Ai和Bi,表示挂饰i有Ai个挂钩,安装后会获得Bi的喜悦值。
Output
输出一行一个整数,表示手机上连接的挂饰总和的最大值
Sample Input
50 42 -21 -10 10 3
Sample Output
5
HINT
将挂饰2直接挂在手机上,然后将挂饰1和挂饰5分别挂在挂饰2的两个挂钩上,可以获得最大喜悦值4-2+3=5。
1<=N<=2000
0<=Ai<=N(1<=i<=N)
-106<=Bi<=106(1<=i<=N)
分析:单纯考虑第一个挂饰,决策的顺序有很大的影响,这样会陷入暴力的方案中去,按照挂钩排序,这样就貌似不用考虑是否没有地方放了。考虑前 i 个物品, 是否能转移呢? 加一维 j 当前有多少挂钩,
保证 j >=1 ,初始化状态 其他 负很多,这样才能将开始就是负数的状态转移上来。
可以发现,这个过程其实就是一个01背包刷表过程。
/************************************************************** Problem: 4247 User: TreeDream Language: C++ Result: Accepted Time:2180 ms Memory:17012 kb****************************************************************/ #include <bits/stdc++.h> using namespace std; const int inf =0x3f3f3f3f; int n;struct Node { int a,b; bool operator < (const Node& rhs) const { return a > rhs.a; }}nodes[2005]; int dp[2005][2005]; int main(){ //freopen("in.txt","r",stdin); scanf("%d",&n); for(int i = 1; i <=n; i++) scanf("%d%d",&nodes[i].a,&nodes[i].b); sort(nodes+1,nodes+1+n); for(int i = 0; i <=n; i++) memset(dp[i],-inf,sizeof(dp[i]));? dp[0][1] = 0; for(int i=1;i<=n;i++) { for(int j=n;j>=0;j--) { int tmp = max(j-nodes[i].a,0); dp[i][j] = max(dp[i-1][j],dp[i-1][tmp+1]+nodes[i].b); } } int ans = 0; for(int i = 0; i <= n; i++) ans = max(ans,dp[n][i]); printf("%d\n",ans); return 0;}
其实还有一些题目要推荐的:今天上课太热了,脑子有点晕,明天更新这一块的有趣的内容。
时间: 2024-09-30 07:09:55