题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6804
给出两个班的人,每个人具有力量与颜值两个属性。要求在两个班级中分别选取任意个人,使得各班力量总和相同,求总颜值的最大值。
01背包 ?——> 取负优化
由于数据较大,直接求和的话我们的内存伤不起。
因而选择将一个班级同学的力量取负,转而求DP[0]的max。
又根据数组下标非负性,找个maxn再向右挪一波——> 求DP[mid]
一寸长 一寸强
1 #include<iostream>
2 #include<algorithm>
3 #include<cstring>
4 #include<cmath>
5 #include<iomanip>
6 #include<vector>
7 #include<random>
8
9 #define ll long long
10 #define INF 1ll << 62//
11 using namespace std;
12 const int maxn = 1e5 + 10;
13 //通过随机数组元素の顺序,达到缩小maxn的目的
14 //取(-5e4,5e4),原本答案位于dp[0],但由于dp数组的正号性,直接右移5e4,取maxn=1e5
15 struct node
16 {
17 ll u;
18 ll v;
19 };
20
21 int n, m;
22 ll dp[maxn];
23
24 int main(){
25 int T;cin >> T;
26 while(T--)
27 {
28 cin >> n >> m;
29 vector<node>v;
30 ll a, b;
31 for(int i = 1 ; i <= n ; i++){
32 scanf("%lld %lld",&a,&b);
33 v.push_back({a ,b});
34 }
35 for(int i = 1 ; i <= m ; i++){
36 scanf("%lld %lld",&a,&b);
37 v.push_back({-a ,b});
38 }//B班改为负
39
40 random_shuffle(v.begin(),v.end());//数组随机化
41 for(int i = 0 ; i < maxn ; i++) dp[i] = -INF;
42
43 const int mid = 5e4;
44 dp[mid] = 0;
45 for(int i = 0 ; i < m + n ; i++){//vector从零开始
46 if(v[i].u > 0){//等号放在下面好像不行
47 for(int j = mid * 2; j >= v[i].u ; j--){//j - v[i].u >= 0
48 dp[j] = max(dp[j], dp[j - v[i].u] + v[i].v);
49 }
50 }else if(v[i].u < 0){
51 for(int j = 0 ; j <= mid * 2 + v[i].u ; j++){//j - v[i].u <= maxn
52 dp[j] = max(dp[j], dp[j - v[i].u] + v[i].v);
53 }
54 }else{//长得好看但没力气的人处处受欢迎。社会风气√
55 for(int j = 0 ; j <= mid * 2 ; j++){
56 dp[j] = max(dp[j], dp[j] + v[i].v);
57 }
58 }
59 //正负两组分别向mid方向汇聚,- ... MID ... +
60 }
61
62 printf("%lld
",dp[mid]);
63
64 }
65
66 return 0;
67 }
68 //数对是真好用