Luogu1282 多米诺骨牌 DP、背包

题目传送门

题意:给出$N$个在$-5$到$5$之间的数字,你可以对任意一个数字取相反数,问最少取多少次相反数可以使得它们的和在所有方案中最接近$0$。$N \leq 10^4$


拔河型01背包

这种背包中物品的取法有变化:一种是取正值,一种是取负值。我们仍然可以像原来的$01$背包一样进行转移,但是因为转移的方向不是固定的,所以不能像原来的一维数组DP一样进行DP,需要一个辅助数组装新转移出来的状态。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int num[10001] , numa[10001];
 4 inline int fast_read()
 5 {
 6     char ch = getchar();
 7     int a = 0;
 8     while(!isdigit(ch))    ch = getchar();
 9     while(isdigit(ch))    a = a * 10 + ch - '0' , ch = getchar();
10     return a;
11 }
12 int main()
13 {
14     int maxC = 0;
15     memset(num , -1 , sizeof(num));
16     num[5000] = 0;
17     for(int n = fast_read() ; n ; n--)
18     {
19         int a = fast_read() , b = fast_read();
20         for(int i = 5000 - maxC - (int)abs(a - b) ; i <= 5000 + maxC + (int)abs(a - b) ; i++)
21             numa[i] = -1;
22         for(int i = 5000 - maxC ; i <= 5000 + maxC ; i++)
23             if(num[i] != -1)
24             {
25                 numa[i + a - b] = numa[i + a - b] == -1 ? num[i] : min(num[i] , numa[i + a - b] );
26                 numa[i - a + b] = numa[i - a + b] == -1 ? num[i] + 1 : min(num[i] + 1 , numa[i - a + b]);
27             }
28         maxC += (int)abs(a - b);
29         for(int i = 5000 - maxC ; i <= 5000 + maxC ; i++)
30             num[i] = numa[i];
31     }
32     for(int dirA = 5000 , dirB = 5000 ; ; dirA++ , dirB--)
33         if(num[dirA] != -1 || num[dirB] != -1)
34         {
35             if(num[dirA] == -1)    cout << num[dirB];
36             else    if(num[dirB] == -1)    cout << num[dirA];
37             else    cout << min(num[dirB] , num[dirA]);
38             break;
39         }
40     return 0;
41 }

五个月前我竟是画风清奇的压行+大括号换行党

猜你喜欢

转载自www.cnblogs.com/Itst/p/9775363.html