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;
}
此生无悔入OI 来生AK IOI

浙公网安备 33010602011771号