【洛谷习题】多米诺骨牌

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


 

花了好长时间终于写出了这道题,主要是状态转移方程比较奇葩,类似于背包问题,难以想到。

呃呃,写得DP不多,对于如何想出状态转移方程还没什么心得,主要是往之前见过的模型上靠。这道题的话,其实可以稍微转化一下设问,变成有n个数,每次操作可以将其变为相反数,问最少操作几次可以使总和的绝对值最小。设dp[i][j]为考虑到第i个数,总和为j时最少的操作次数。状态转移方程为dp[i][j]=min(dp[i-1][j-num[i]],dp[i-1][j+num[i]]+1)。因为是取最小值,一开始要把dp数组初始化成inf,还要将未进行操作的dp初始化为0。反正代码细节也还是有的。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 const int maxn = 1e3 + 5, maxm = 1e4 + 5, inf = 0x3f3f3f3f;
 9 
10 int num[maxn], dp[maxn][maxm], mm[maxn];
11 
12 inline int map(int x) {
13     return x + 5e3 + 1;
14 }
15 
16 int main() {
17     int n, a, b, sum = 0;
18     scanf("%d", &n);
19     for (int i = 1; i <= n; ++i) {
20         scanf("%d%d", &a, &b);
21         num[i] = a - b;
22     }
23     memset(dp, inf, sizeof(dp));
24     for (int i = 0; i <= n; ++i) {
25         dp[i][map(sum)] = 0;
26         sum += num[i];
27         mm[i] = mm[i - 1] + abs(num[i]);
28     }
29     for (int i = 1; i <= n; ++i)
30         for (int j = -mm[i]; j <= mm[i]; ++j)
31             dp[i][map(j)] = min(dp[i - 1][map(j - num[i])], dp[i - 1][map(j + num[i])] + 1);
32     for (int i = 0; i <= mm[n]; ++i)
33         if (dp[n][map(i)] != inf || dp[n][map(-i)] != inf) {
34             printf("%d", min(dp[n][map(i)],dp[n][map(-i)]));
35             return 0;
36         }
37     return 0;
38 }
AC代码

 

posted @ 2018-09-08 15:43  Mr^Kevin  阅读(372)  评论(0编辑  收藏  举报