Luogu P1282 多米诺骨牌

 P1282 多米诺骨牌

题目描述

多米诺骨牌有上下2个方块组成,每个方块中有1~6个点。现有排成行的

上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|。例如在图8-1中,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。

 

输出格式:

 

输出文件仅一行,包含一个整数。表示求得的最小旋转次数。

 

输入输出样例

输入样例#1:
4
6 1
1 5
1 3
1 2
输出样例#1: 
1

 

 

  这是一道背包题。。

  经过一个月的培训,我终于背包题都不会做了。

  这道题几天做出来你信?

 

  问差最小时,旋转次数最少是多少。那么我们就把每个差所需要最小旋转次数给搞出来。

  dp[i][j] 表示 前i个牌,差值为j时,所需要的最小旋转次数。

  转移方程: dp[i][j] = min(dp[i-1][j+dis], dp[i-1][j-dis]+1)

  这里的dis就是s1[i] - s2[i]。

  

  由于数组的下标不能为负数,所以数组第二维用了个小技巧。具体请看程序。

 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 int n, s1[1005], s2[1005];
 5 int dp[1005][10050];
 6 
 7 const int N = 5000;
 8 
 9 int minn(int a, int b)
10 {
11     return ((a < b) ? a : b);
12 }
13 
14 int main()
15 {
16     int dis, ans;
17     
18     scanf("%d", &n);
19     for(int i=1; i<=n; i++)
20     {
21         scanf("%d%d", &s1[i], &s2[i]);
22     }
23     
24     //设置dp为最大值。
25     for(int i=0; i<=1000; i++)
26         for(int j=0; j<=10005; j++)
27             dp[i][j] = 1000;
28     
29     //0+N就相当于0
30     dp[0][0+N] = 0;
31     
32     for(int i=1; i<=n; i++)
33     {
34         for(int j=-5000; j<=5000; j++)
35         {
36             dis = s1[i] - s2[i];
37             dp[i][j+N] = minn(dp[i-1][j+dis+N], dp[i-1][j-dis+N]+1);
38         }
39     }
40     
41     for(int i=0; i<= 5000; i++)
42     {
43         ans = minn(dp[n][-i+N], dp[n][i+N]);
44         if(ans < 1000)
45         {
46             printf("%d", ans);
47             break;
48         }
49     }
50     
51     return 0;
52 }

 

posted @ 2017-10-27 00:01  yBaka  阅读(162)  评论(0编辑  收藏  举报