bzoj4247:挂饰

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

5
0 4
2 -2
1 -1
0 1
0 3

Sample Output

5

HINT

将挂饰2直接挂在手机上,然后将挂饰1和挂饰5分别挂在挂饰2的两个挂钩上,可以获得最大喜悦值4-2+3=5。

1<=N<=2000

0<=Ai<=N(1<=i<=N)

-10^6<=Bi<=10^6(1<=i<=N)
 
1A的一道题,好开心
题解:
看到这道题,经验主义感觉应该是dp,可是我一开始并不知道该怎么dp
想到在确定了最大情况下挂多少挂件后,挂件挂的顺序并没有影响,于是先将挂件根据挂钩从大到小排序
之后想状态应是什么
曾经想过把挂件间的连接关系当成一棵树,类似树形dp做,但是不好实现,子树中可能有重复的挂件
然后大概就是考虑每一个挂件是挂还是不挂
慢慢想到了可以用记忆化搜索,状态是从某一个挂件开始往后,在还有多少挂钩的可获得的最大喜悦值(似乎说的不太明白,看代码就一目了然了)
做的时候遇到了一个问题,就是还剩的挂钩数可能会很大。但很快发现剩的挂钩数若大于n是毫无意义的,于是所有大于n的都当成n就好了
 
总结一下思路:
感觉是dp -> 思考状态,针对每一个挂钩考虑 -> 记忆化搜索 -> 改进细节
 
代码:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<string.h>
 5 #define INF 100000000
 6 using namespace std;
 7 
 8 const int MAXN = 2005;
 9 int n;
10 struct item{
11     int a,b;
12     bool operator < (const item &x) const{
13         return x.a>a;     
14     }
15 }d[MAXN];
16 bool cmp(item x,item y){
17     return y<x;
18 }
19 
20 int dp[MAXN][MAXN],vis[MAXN][MAXN];
21 int dfs(int num,int free){
22     if(free>n) free=n;
23     if(vis[num][free]) return dp[num][free]; 
24     if(free==0) return 0;
25     if(num==n+1) return 0; 
26     int ret=-INF;
27     ret=max(ret,dfs(num+1,free-1+d[num].a)+d[num].b);
28     ret=max(ret,dfs(num+1,free));
29     vis[num][free]=1;
30     return dp[num][free]=ret;
31 }
32 
33 int main()
34 {
35     int i,j;
36     scanf("%d",&n);
37     for(i=1;i<=n;i++) scanf("%d%d",&d[i].a,&d[i].b);
38     sort(d+1,d+1+n,cmp);
39 
40     printf("%d
",dfs(1,1));
41 
42     return 0;    
43 }
View Code
既然选择了远方,便只顾风雨兼程
原文地址:https://www.cnblogs.com/lindalee/p/7670058.html