P1282 多米諾骨牌

P1282 多米諾骨牌

題目描述
多米諾骨牌有上下2個方塊組成,每一個方塊中有1~6個點。現有排成行的ios

上方塊中點數之和記爲S1,下方塊中點數之和記爲S2,它們的差爲|S1-S2|。例如在圖8-1中,S1=6+1+1+1=9,S2=1+5+3+2=11,|S1-S2|=2。每一個多米諾骨牌能夠旋轉180°,使得上下兩個方塊互換位置。 編程用最少的旋轉次數使多米諾骨牌上下2行點數之差達到最小。編程

Solution

先明確題意:
每一個物品有兩個狀態: 正着的和倒着的
求最小差值意義下的最小旋轉次數數組

首先看這個差值最小, 發現下值 = 總值 - 上值, 因而咱們統計一側和便可計算差值
而後設計一下狀態, 題目求最小旋轉次數, 那麼dp數組表示的應該是最小次數, 又有最小差值限制顯然要引入一維一側和做爲狀態
設計dp狀態的關鍵是看 以下狀態是否只對應一個最值
因而 \(dp[i][j]\) 表示考慮前 \(i\) 個, 上側和爲 \(j\) 的最小旋轉次數
邊界爲 第一個不轉 ---> \(dp[1][up[1]] = 0\)
轉 ---> \(dp[1][down[1]] = 1\)
注意當 \(up[1] == down[1]\) 時不用旋轉, 兩個值都爲 0優化

轉移直接看轉不轉便可, 相似 01揹包
注意 \(j\) 的狀態最大有 \(6n\)
而後考慮優化的話能夠讓最大狀態爲 \(\sum_{i = 1}^{n}max(up_{i}, down_{i})\)
還能夠滾動數組
懶就不寫了spa

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 2019, inf = 1e9;
int num;
int a[maxn], b[maxn], sum;
int dp[maxn][maxn * 6];//表示前i個骨牌,上面和爲j的最小交換數
void init(){
    num = RD();
    REP(i, 1, num)a[i] = RD(), b[i] = RD(), sum += a[i] + b[i];
    REP(i, 1, num)REP(j, 1, num * 6)dp[i][j] = inf;
    if(a[1] == b[1])dp[1][a[1]] = dp[1][b[1]] = 0;
    else dp[1][a[1]] = 0, dp[1][b[1]] = 1;
    }
void solve(){
    REP(i, 1, num){
        REP(j, 1, num * 6){//最多狀態數
            if(dp[i][j] == inf)continue;//防越界就打了個刷表法
            dp[i + 1][j + a[i + 1]] = min(dp[i + 1][j + a[i + 1]], dp[i][j]);//不轉
            dp[i + 1][j + b[i + 1]] = min(dp[i + 1][j + b[i + 1]], dp[i][j] + 1);//轉
            }
        }
    int minS = inf, ans;
    REP(i, 1, num * 6){
        if(dp[num][i] == inf)continue;
        int now = abs((sum - i) - i);
        if(now < minS){
            minS = now;
            ans = dp[num][i];
            }
        else if(now == minS)ans = min(ans, dp[num][i]);
        }
    printf("%d\n", ans);
    }
int main(){
    init();
    solve();
    return 0;
    }
相關文章
相關標籤/搜索