当前位置: 代码迷 >> 综合 >> DP P1282 多米诺骨牌
  详细解决方案

DP P1282 多米诺骨牌

热度:1   发布时间:2024-01-15 08:42:59.0

题目描述

多米诺骨牌有上下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

 

题目分析:

DP还是理解不够,背包还是没得心运手啊。

可以转化为01背包问题,只不过我们必须要选,该题的上面a[i]和下面b[i]差值的累积和不知道,但我们知道最大为5000(题目暗含),好,我们把这5000看成背包的容量,

但,我们不要忘了累加差值还有负数,所以就扩大为-5000~5000,但数组下标不能为负数,所以,定义个常数5000即可。

则我们定义f[i][j]为前i组数最少交换次数得到最小差值累加和j

状态转移方程:f[i][j+N]=min(f[i-1][j+(a[i]-b[i])+N],f[i-1][j-(a[i]-b[i])+N])

别忘了初始化f[0][N+0]=0

代码实现:

#include<bits/stdc++.h>
using namespace std;
int f[1005][13002];
const int N=5000;          //差值最大5000,因为数组下标不能为负数,所以加一个最大值
int main()
{int n,a[1005],b[1005];int i,j;cin>>n;for(i=1;i<=n;i++)cin>>a[i]>>b[i];memset(f,127,sizeof(f));f[0][N+0]=0;for(i=1;i<=n;i++)                     //枚举前i个for(j=-5000;j<=5000;j++)           //枚举可能加到的和{int dis=a[i]-b[i];f[i][j+N]=min(f[i-1][j+dis+N],f[i-1][j-dis+N]+1);//换与不换,但必须选}int minn;for(i=0;i<=5000;i++){minn=min(f[n][i+N],f[n][N-i]);//不知道累加的差和具体在哪里,慢慢查找if(minn<=1000)                //最多调换1000次{cout<<minn;break;}}return 0;
}