洛谷P1282 多米诺骨牌
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;
}

浙公网安备 33010602011771号