洛谷P1282 多米诺骨牌 题解
洛谷P1282 多米諾骨牌 題解
題目鏈接:P1282 多米諾骨牌
題意:
多米諾骨牌由上下 222 個方塊組成,每個方塊中有 1~61\sim61~6 個點。現有排成行的上方塊中點數之和記為 S1S_1S1?,下方塊中點數之和記為 S2S_2S2?,它們的差為 ∣S1?S2∣\left|S_1-S_2\right|∣S1??S2?∣。如圖,S1=6+1+1+1=9S_1=6+1+1+1=9S1?=6+1+1+1=9,S2=1+5+3+2=11S_2=1+5+3+2=11S2?=1+5+3+2=11,∣S1?S2∣=2\left|S_1-S_2\right|=2∣S1??S2?∣=2。每個多米諾骨牌可以旋轉 180°180°180°,使得上下兩個方塊互換位置。請你計算最少旋轉多少次才能使多米諾骨牌上下 222 行點數之差達到最小。
對于圖中的例子,只要將最后一個多米諾骨牌旋轉 180°180°180°,即可使上下 222 行點數之差為 000。
注意到我們其實并不關心 S1,S2S_1,S_2S1?,S2? 的值,而是關心他們的差值
這個絕對值似乎不好處理,其實只要把正負的情況取個min就可以了
設 dp[i][j]dp[i][j]dp[i][j] 表示只考慮前 iii 個骨牌,差值為 jjj 時的最小翻轉數
這里的 jjj 定義為 S1?S2S_1-S_2S1??S2? 或者 S2?S1S_2-S_1S2??S1? 其實沒啥區別,不過下面代碼為前者
不難發現
dp[i][j]=min?(dp[i?1][j?a[i]+b[i]]+1,dp[i?1][j+a[i]?b[i]])dp[i][j]=\min(dp[i-1][j-a[i]+b[i]]+1,dp[i-1][j+a[i]-b[i]]) dp[i][j]=min(dp[i?1][j?a[i]+b[i]]+1,dp[i?1][j+a[i]?b[i]])
注意到差值最大 500050005000 ,為了避免亂七八糟討論,就直接循環 ?5000~5000-5000 \sim 5000?5000~5000 就好啦
差值可能為負所以數組整體平移一下,然后整個填表法滾一滾啥的就好了
這里好像刷表法寫起來不太安全就不寫了,雖然沒啥問題,但是不算簡潔吧(逃
代碼:
#include <bits/stdc++.h> using namespace std; #define int long long #define INF 0x3f3f3f3f3f3f3f3f #define N (int)(1e3+15) const int bd=5e3+15; int n,dp[2][20*N],a[N],b[N]; signed main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);// freopen("check.in","r",stdin);// freopen("check.out","w",stdout);memset(dp,0x3f,sizeof(dp));cin >> n;dp[0][bd]=0;for(int i=1; i<=n; i++)cin >> a[i] >> b[i];for(int i=1; i<=n; i++){int cur=i&1,pre=cur^1;memset(dp[cur],0x3f,sizeof(dp[cur]));for(int j=-5000; j<=5000; j++)dp[cur][j+bd]=min(dp[pre][j+a[i]-b[i]+bd]+1,dp[pre][j-a[i]+b[i]+bd]);}for(int i=0; i<=5000; i++){int t=min(dp[n&1][i+bd],dp[n&1][-i+bd]);if(t<=n)return cout << t << endl,0;}return 0; }轉載請說明出處
總結
以上是生活随笔為你收集整理的洛谷P1282 多米诺骨牌 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: canvas线条背景(抽象画布可视化,利
- 下一篇: 什么叫系统后门?后门与漏洞有什么区别?