poj1717 Dominoes

Description

A domino is a flat, thumbsized tile, the face of which is divided into two squares, each left blank or bearing from one to six dots. There is a row of dominoes laid out on a table: 

The number of dots in the top line is 6+1+1+1=9 and the number of dots in the bottom line is 1+5+3+2=11. The gap between the top line and the bottom line is 2. The gap is the absolute value of difference between two sums. 

Each domino can be turned by 180 degrees keeping its face always upwards. 

What is the smallest number of turns needed to minimise the gap between the top line and the bottom line? 

For the figure above it is sufficient to turn the last domino in the row in order to decrease the gap to 0. In this case the answer is 1. 
Write a program that: computes the smallest number of turns needed to minimise the gap between the top line and the bottom line.

Input

The first line of the input contains an integer n, 1 <= n <= 1000. This is the number of dominoes laid out on the table. 

Each of the next n lines contains two integers a, b separated by a single space, 0 <= a, b <= 6. The integers a and b written in the line i + 1 of the input file, 1 <= i <= 1000, are the numbers of dots on the i-th domino in the row, respectively, in the top line and in the bottom one. 

Output

Output the smallest number of turns needed to minimise the gap between the top line and the bottom line.

Sample Input

4
6 1
1 5
1 3
1 2

Sample Output

1

f[i][j][k] : 前i片骨牌,上面的总和减去下面的总和为j时是否能达成k步完成。

初始化条件:

f[i][j][k] = 0

f[0][0][0] = 1

转移方程:

f[i][j][k] |= f[i - 1][j - a[i] + b[i]][k] | f[i - 1][j - b[i] + a[i]][k - 1]

 

 

优化一维状态:

f[i][j] : 前i片骨牌,上面的总和减去下面的总和为j时最小步骤

初始化条件:

f[0][0] = 0

f[i][j] = INF (i != 0 && j != 0)

转移方程:

f[i][j] = min(f[i - 1][j - a[i] + b[i], f[i - 1][j - b[i] + a[i] + 1)

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <queue>
 7 #include <vector>
 8 
 9 using namespace std;
10 
11 #define f(i, j) f[i][6005 + j]
12 
13 int f[1010][6010 * 2], n, a[1010], b[1010];
14 
15 int main() {
16   scanf("%d", &n);
17   for(int i = 1 ; i <= n ; i ++) {
18     scanf("%d%d", &a[i], &b[i]);
19   }
20   memset(f, 0x3f, sizeof(f));
21   f(0, 0) = 0;
22   for(int i = 1 ; i <= n ; i ++) {
23     for(int j = -6000 ; j <= 6000 ; j ++) {
24       f(i, j) = min(f(i - 1, j - a[i] + b[i]), 1 + f(i - 1, j - b[i] + a[i]));
25     }
26   }
27   for(int j = 0 ; j <= 6000 ; j ++) {
28     if(min(f(n, j), f(n, -j)) < 0x3f3f3f3f) {
29       printf("%d\n", min(f(n, j), f(n, -j)));
30       break;
31     }
32   }
33 }
View Code

 

转载于:https://www.cnblogs.com/KingSann/articles/7398771.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值