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







    这道题目难,首先选与不选不会对后面选择可能产生干扰,但对结果会产生影响一般是用背包,这样看这道题就是一道01背包题。

    但是第一维维护的是第几张牌,第二维维护什么值就需要考虑一下,由于他题目每张牌最大差值只有5,且最多只有1000张牌,那,为什么差值不是5000呢?

    如果你是比赛经验比较丰富的选手,你的第二维可能就会选择维护差值,dp[i][j]等于到第i张牌差值为j的最小交换次数。如果你是选择第二维维护次数,dp[i][j]等于到第i张牌交换j次的最小差值。

    但是这会遇到一个问题,就是如果一个位置,交换与不交换的差值绝对值相同,那应当要存下正负两个值,下次就要4个值,最坏情况2的1000次方,但是因为单张牌最大差值只有5,最多1000张牌,最多5000*2(正负)个值,内部有很多值是相同的,由此也会得出第二维可能要维护差值而不是交换次数(但是一个dalao说这种思路可以用bitset来解决orz),代码:

#include<bits/stdc++.h>

using namespace std;

const int MAXN=1010;
int dp[MAXN][20*MAXN],a[MAXN],b[MAXN];
int inf, N = 5000;

int main(){
    int n, i, j, k;
    cin >> n;
    inf = 0x7F;
    for(i = 1;i <= n; i ++)
    {
        cin >> a[i] >> b[i];
    }

    memset(dp ,0x3f, sizeof(dp));

    dp[0][0] = 0;
    dp[0][0+N] = 0;
    for(i = 1; i <= n; i ++)
    {
        int temp = a[i] - b[i];
        for(j = i * 6; j >= -(i * 6); j --)
        {
            dp[i][j+N] = min(dp[i-1][j+temp+N], dp[i-1][j-temp+N]+1);
        }
    }
    int ans;
    for(i = 0; i <= n * 6 ; i ++)
    {
        ans = min(dp[n][i+N], dp[n][-i+N]);
        if(ans < 1000)
            break;
    }
    cout<< ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ant_e_zz/article/details/80297080