第一篇题解,纪念!
题目描述
多米诺骨牌由上下 2 个方块组成,每个方块中有 1∼6 个点。现有排成行的上方块中点数之和记为 S1,下方块中点数之和记为 S2,它们的差为 ∣S1−S2∣。如图,S1=6+1+1+1=9,S2=1+5+3+2=11,∣S1−S2∣=2。每个多米诺骨牌可以旋转 180°,使得上下两个方块互换位置。请你计算最少旋转多少次才能使多米诺骨牌上下 2 行点数之差达到最小。

对于图中的例子,只要将最后一个多米诺骨牌旋转 180°,即可使上下 2 行点数之差为 0。
输入格式
输入文件的第一行是一个正整数 n(1≤n≤1000),表示多米诺骨牌数。接下来的 n 行表示 n 个多米诺骨牌的点数。每行有两个用空格隔开的正整数,表示多米诺骨牌上下方块中的点数 a 和 b,且 1≤a,b≤6。
输出格式
输出文件仅一行,包含一个整数。表示求得的最小旋转次数。
思路:dp
dp表
使用一维的dp,dp[i] 表示使上层总和为 i 的最小翻转次数(实际上,选取上层和下层等效)。
依次输入每个牌的上层 t1 和下层 t2,输入的同时进行状态转移,并记录上下牌的总和 sum。
状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include <bits/stdc++.h>
using namespace std; using ll = long long;
inline void minset(int &t, int other) { t = min(t, other); }
inline void maxset(int &t, int other) { t = max(t, other); }
const int inf = 0x7f7f7f7f;
const int N = 1010;
int sum;
int dp[N * 12];
int main() { memset(dp, 0x7f, sizeof dp); dp[0] = 0; int n; cin >> n; int t1, t2; for(int i = 0; i < n; i++) { cin >> t1 >> t2; sum += t1 + t2; for(int i = sum; i >= 0; i--) { if(dp[i] != inf) { minset(dp[i + t1], dp[i]); minset(dp[i + t2], dp[i] + 1); dp[i] = inf; } } } const int mid = sum / 2; int ans = inf;
if(sum % 2) { for(int i = 0; i <= mid; i++) { minset(ans, min(dp[mid - i], dp[mid + 1 + i])); if(ans != inf){ cout << ans << endl; break; } } } else { for(int i = 0; i <= mid; i++) { minset(ans, min(dp[mid - i], dp[mid + i])); if(ans != inf){ cout << ans << endl; break; } } } return 0; }
|