洛谷P1282 多米诺骨牌

Topic Links

Topic Meaning:有n个骨牌,骨牌有带有相应点数的上下俩部分,这n个骨牌的上部分和与下部分和之差的绝对值为m,骨牌可以翻转,即上部分点数与下部分点数交换,则得到最下的m的所需的翻转次数为多少?

 Topic of Solving:线性背包

以第i个骨牌为阶段,前i个骨牌上下部分和的差值为状态,分别对翻与不翻进行状态转移

dp[i][j]表示前i个骨牌m为j;

由于差值可为负值,再结合题目的数据范围,故将表示状态的差值均增大5000,故dp[0][5000]=0为初始状态即前0个骨牌差值为0需翻0次;

从5000即差值为0往两边寻找第一个翻转数小于最大翻转次数1000(即可通过状态转移得到的差值),再判断此差值绝对值的最小翻转数即可;

#include<iostream>
#include<cstring>
using namespace std;
int a[1005],b[1005],dp[1005][10000];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
    memset(dp,0x7F,sizeof(dp));
    dp[0][5000]=0;
    for(int i=1;i<=n;i++)
            for(int j=10000;j>=0;j--){
             int dis=a[i]-b[i];
             if(j-dis<=10000&&j-dis>=0)
             dp[i][j]=min(dp[i][j],dp[i-1][j-dis]);
             if(j+dis>=0&&j+dis<=10000)
             dp[i][j]=min(dp[i][j],dp[i-1][j+dis]+1);
            }
   for(int j=0;;j++)
   if(dp[n][5000+j]<=1000||dp[n][5000-j]<=1000){
    if(dp[n][5000+j]<dp[n][5000-j]) cout<<dp[n][5000+j];
    else cout<<dp[n][5000-j];
    break;
   }
return 0;
}

  

posted @ 2019-08-27 14:16  Evolutw  阅读(121)  评论(0)    收藏  举报