P1282 SSL 1632 多诺米骨牌

题目描述:

题目传送门


解题思路:

本题使用动态规划来求解。

f i , j f_{i,j} fi,j 表示前 i i i 个骨牌构成差值为 j j j 时要旋转骨牌的次数。

a i a_{i} ai 为第 i i i 张骨牌上面的点数, b i b_i bi 为第 i i i 张骨牌下面的点数,则单独考虑第 i i i 张骨牌的差值为 a i − b i a_{i}-b_i aibi。考虑骨牌的旋转,下面的值变成上面的了,上面的值变成下面的,那么差值就变成了 b i − a i b_i-a_i biai
由此,易得动态转移方程:
f i , j = m i n (   f i − 1 , j − ( a i − b i ) , f i − 1 , j − ( b i − a i ) + 1   ) f_{i,j}=min(\ f_{i-1,j-(a_i-b_i)},f_{i-1,j-(b_i-a_i)}+1\ ) fi,j=min( fi1,j(aibi),fi1,j(biai)+1 )
j − ( a i − b i ) j-(a_i-b_i) j(aibi) 表示当 j j j i i i 张骨牌的差时,第 i i i 张骨牌不旋转,前 i − 1 i-1 i1 张骨牌的差。
j − ( b i − a i ) j-(b_i-a_i) j(biai) 表示当 j j j i i i 张骨牌的差时,第 i i i 张骨牌旋转,前 i − 1 i-1 i1 张骨牌的差,翻动次数 + 1 +1 +1
由于第 0 0 0 张骨牌不需要翻转也能得到最小的差值 0 0 0,且只能的到差值 0 0 0,因此 f 0 , 0 = 0 f_{0,0}=0 f0,0=0

接下来要做的就是枚举差值,也就是 j j j 的范围。由于 n n n 最大为1000,点数最大为 6 6 6,因此差值的范围只可能是 − 6000 -6000 6000 6000 6000 6000但是,我们仍能对此范围进行优化。若前 i − 1 i-1 i1 张骨牌的最小差值为 m i n min min,最大差值为 m a x max max,则前 i i i 张骨牌的最小差值只可能达到 m i n − a b s ( a i − b i ) min-abs(a_i-b_i) minabs(aibi),最大差值只可达到 m a x + a b s ( a i − b i ) max+abs(a_i-b_i) max+abs(aibi),再 DP 中动态更改 m i n min min m a x max max,可以大大缩小枚举范围。

找一个最小的并且存在的差值 j j j,即为答案。 因为差值计算涉及绝对值,因此 f i , j f_{i,j} fi,j f i , − j f_{i,-j} fi,j 都有可能被取到,因此需要取一个 m i n min min


CODE:

#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
int n,a[1010],b[1010];
int f[1020][12000]={0};
const int M=4000;
int mn,mx;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	  cin>>a[i]>>b[i];
	memset(f,0x5f,sizeof(f));   //取一个大数来表示当前差不可能达到
	f[0][M]=0;
	mn=mx=0;
	for(int i=1;i<=n;i++)
	  {
	  	int c=mn-abs(a[i]-b[i]),d=mx+abs(a[i]-b[i]);
	  	for(int j=c;j<=d;j++)
	  	  {
	  	  	f[i][j+M]=min(f[i-1][j-(a[i]-b[i])+M],f[i-1][j-(b[i]-a[i])+M]+1);
	  	  	mn=min(mn,j);
	  	  	mx=max(mx,j);
		  }
	  }
	for(int i=0;;i++)
	  if(f[n][M-i]<1600085855||f[n][M+i]<1600085855)
	    {
	    	cout<<min(f[n][M-i],f[n][M+i]);
	    	break;
		}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值