Problem’s Website
- 多米诺骨牌
Solution
这道题可以看做一个线性dp,也可以看做背包问题,根据题意,我们发现一张牌转两次及以上是没有意义的,那么我们可以设f[i][j]表示到第i个数上下点数之差为j的旋转次数,对于i和i+1,状态转移方程为
1
f[i][j] = min(f[i - 1][j - a[i]),f[i - 1][j + a[i]] + 1);
a[i]为上下一张牌上下点数之差,为了防止数组下标出现负数,我们把每个j加上一个num,最后通过枚举找到差值最小的f[i][j],记录最小转动次数。
Code
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
using namespace std;
int sc() {
int xx = 0, ff = 1; char cch = gc;
while(cch < '0' || cch > '9') {
if(cch == '-') ff = -1; cch = gc;
}
while(cch >= '0' && cch <= '9') {
xx = (xx << 1) + (xx << 3) + (cch ^ '0'); cch = gc;
}
return xx * ff;
}
int n, ans;
int a[1010], f[1010][10010];
int main() {
n = sc();
for(int i = 1; i <= n; i++) {
int x = sc(), y = sc();
a[i] = x - y;
}
memset(f, 0x7f, sizeof(f));
f[0][0 + num] = 0;
for(int i = 1; i <= n; i++) {
for(int j = -5000 ; j <= 5000; j++) {
f[i][j + num] = min(f[i - 1][j + num - a[i]], f[i - 1][j + num + a[i]] + 1);
}
}
for(int i = 0; i <= 5000; i++) {
ans = min(f[n][i + num], f[n][num - i]);
if(ans <= 1000) {
printf("%d\n", ans);
return 0;
}
}
return 0;
}
rp++