P1282

多米诺骨牌

题目描述

多米诺骨牌由上下 \(2\) 个方块组成,每个方块中有 \(1\sim6\) 个点。现有排成行的上方块中点数之和记为 \(S_1\),下方块中点数之和记为 \(S_2\),它们的差为 \(\left|S_1-S_2\right|\)。如图,\(S1=6+1+1+1=9\)\(S2=1+5+3+2=11\)\(\left|S_1-S_2\right|=2\)。每个多米诺骨牌可以旋转 \(180°\),使得上下两个方块互换位置。请你计算最少旋转多少次才能使多米诺骨牌上下 \(2\) 行点数之差达到最小。

对于图中的例子,只要将最后一个多米诺骨牌旋转 \(180°\),即可使上下 \(2\) 行点数之差为 \(0\)

输入格式

输入文件的第一行是一个正整数 \(n(1\leq n\leq 1000)\),表示多米诺骨牌数。接下来的 \(n\) 行表示 \(n\) 个多米诺骨牌的点数。每行有两个用空格隔开的正整数,表示多米诺骨牌上下方块中的点数 \(a\)\(b\),且 \(1\leq a,b\leq 6\)

输出格式

输出文件仅一行,包含一个整数。表示求得的最小旋转次数。

样例 #1

样例输入 #1

4
6 1
1 5
1 3
1 2

样例输出 #1

1
这题着实NB
首先有个性质交换前后两行的和固定 所以说只用记录一行的和就行了
f[i][j]:前i个 第一行和为j的最小交换次数
最后枚举更新差值和次数即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[1005],b[1005],s1[1005],s2[1005];
int f[1005][6005];
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i]>>b[i],s1[i]=s1[i-1]+a[i],s2[i]=s2[i-1]+b[i];
	memset(f,0x3f,sizeof(f));
	int INF=f[0][0];
	f[1][a[1]]=0,f[1][b[1]]=1;
	for(int i=2;i<=n;i++)
		for(int j=0;j<=6000;j++)
		{
			if(j-a[i]>=0)f[i][j]=min(f[i][j],f[i-1][j-a[i]]);
			if(j-b[i]>=0)f[i][j]=min(f[i][j],f[i-1][j-b[i]]+1);
		}
	int minn1=INT_MAX,minn2=INT_MAX;
	for(int i=0;i<=s1[n]+s2[n];i++)
	{
		if(f[n][i]==INF)continue;
		int s=s1[n]+s2[n];
		if(abs(i-(s-i))<minn2)
		{
			minn2=abs(i-(s-i));
			minn1=f[n][i];
		}
		else if(abs(i-(s-i))==minn2)
		{
			minn1=min(minn1,f[n][i]);
		}
	}
//	cout<<minn2<<"\n";
	cout<<minn1<<'\n';
	return 0;
}
posted @ 2023-01-11 21:58  PKU_IMCOMING  阅读(10)  评论(0)    收藏  举报