洛谷P1282 多米诺骨牌【线性dp】

题目https://www.luogu.org/problemnew/show/P1282

题意:

给定n个牌,每个牌有一个上点数和下点数。可以通过旋转改变交换上下点数。

问使得上点数之和和下点数之和的差的绝对值最小的最少旋转方法。

思路:

新增一个牌,对于点数差的贡献是+a-b或-a+b

所以很自然的可以写出状态转移方程dp[i][s]=min(dp[i-1][s-a+b], dp[i-1][s+a-b]+1)

需要注意的是第二维放的是差,有可能是负数,所以要加一个偏移量。

而s的范围应该没有限制,从最小到最大值。

最后在0~最大值中寻找一个最小的s(表示的是绝对值),使得dp[n][s]或dp[n][-s]是有值的,就是答案。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<set>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<cmath> 
 9 #include<stack>
10 #include<queue>
11 #include<iostream>
12 
13 #define inf 0x7fffffff
14 using namespace std;
15 typedef long long LL;
16 typedef pair<string, string> pr;
17 
18 int n;
19 const int maxn = 1005;
20 const int mx = 7000;
21 int a[maxn], b[maxn];
22 int dp[maxn][mx * 2];
23 
24 int main()
25 {
26     scanf("%d", &n);
27     for(int i = 1; i <= n; i++){
28         scanf("%d%d", &a[i], &b[i]);
29     }
30     memset(dp, 0x3f, sizeof(dp));
31     
32     dp[0][mx] = 0;
33     for(int i = 1; i <= n; i++){
34         for(int j = -mx; j <= mx; j++){
35             dp[i][j + mx] = min(dp[i - 1][j - a[i] + b[i] + mx], dp[i - 1][j + a[i] - b[i] + mx] + 1);
36         }
37     }
38     
39     for(int i = 0; i <= mx; i++){
40         int ans = min(dp[n][i + mx], dp[n][-i + mx]);
41         if(ans < mx){
42             printf("%d\n", ans);
43             break;
44         }
45     }
46     
47     return 0; 
48 }

猜你喜欢

转载自www.cnblogs.com/wyboooo/p/10823642.html