【动态规划】多米诺骨牌

题目描述

有一种多米诺骨牌是平面的,其正面被分成上下两个部分,每一部分的表面或者为空,或者背标上1至6个点。现在有一行多米诺骨牌排列在桌面上:

顶行(上行)骨牌的点数之和为6+1+1+1=9;底行(下行)骨牌的点数之和为1+5+3+2=11。顶行和底行的差值是2,这个差值是上下两行点数之和的差的绝对值。每个多米诺骨牌都可以上下翻转交换,即上部变为下部,下部变为上部。
现在的任务是,以最少的翻转次数,使得顶行和底行之间的差值最小。对于上面这个例子,我们只需要翻转最后一个骨牌,就可以使得顶行和底行的差值为0。所以这个例子的答案为1。

输入

第1行是一个整数n(1≤n≤1000),表示有n个多米诺骨牌在桌面上排成一行。接下来总共有n行,每行包含两个整数a、b(0≤a,b≤6,中间用空格分开)。第i+1行的a、b分别表示第i个多米诺骨牌的上部和下部的点数(0表示空)。

输出

只有一个整数,这个整数表示翻动骨牌的最少次数,从而使得顶行和底行的差值最小。

样例输入 复制
4
6 1
1 5
1 3
1 2
样例输出 复制
1

参考代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,i,j,a[1005][4],dp[1005][6005],ans,s,min1,si,sj,s1;
bool f[1005][6005];
int main()
{
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i][1],&a[i][2]);
		s+=a[i][1];
		s1+=a[i][2];
	}
	for(i=0;i<=n;i++)
	{
		for(j=0;j<=s+s1;j++)
		{
			dp[i][j]=1010;
		}
	}
	dp[0][0]=0;
	for(i=0;i<=n;i++)
	{
		for(j=0;j<=s+s1;j++)
		{
			if(j+a[i+1][2]<=6*n&&dp[i][j]!=1010)
			{
				if(f[i+1][j+a[i+1][1]]==0)
				{
					f[i+1][j+a[i+1][1]]=1;
					dp[i+1][j+a[i+1][1]]=dp[i][j];
				}
				else
				dp[i+1][j+a[i+1][1]]=min(dp[i+1][j+a[i+1][1]],dp[i][j]);
				if(f[i+1][j+a[i+1][2]]==0)
				{
					f[i+1][j+a[i+1][2]]=1;
					dp[i+1][j+a[i+1][2]]=dp[i][j]+1;
				}
				else
				dp[i+1][j+a[i+1][2]]=min(dp[i+1][j+a[i+1][2]],dp[i][j]+1);
			}
			
		}
	}
	for(j=0;j<=6*i;j++)
	{
		if((s+s1)/2>j&&dp[i][(s+s1)/2-j]!=1010)
		{
			printf("%d",dp[i][(s+s1)/2-j]);
			return 0;
		}
		if((s+s1)/2+j<6*i&&dp[i][(s+s1)/2+j]!=1010)
		{
			printf("%d",dp[i][(s+s1)/2+j]);
			return 0;
		}
	}
	return 0;
}
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值