题目链接:https://www.luogu.org/problemnew/show/P1282
DP方程很难推,因为状态很多。
dp[i][j]表示前i个骨牌中第一行和为j,最小要翻多少次骨牌
那么dp[1][b[1]] = 1,dp[1][a[1]] = 0,这很显然。
因为骨牌点数有1,2,3,4,5,6。所以我们直接枚举j(0~6*n),全部放在dp里面
最后根据枚举sum,推出答案(说实话我也没太看明白)
代码:
#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9+7;
const int maxn = 1010;
int a[maxn],b[maxn];
int dp[maxn][maxn*6];
int main()
{
int n;
cin>>n;
int sum = 0;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
sum += a[i]+b[i];
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=6*n;j++)
{
dp[i][j] = INF;
}
}
dp[1][b[1]] = 1;
dp[1][a[1]] = 0;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=6*n;j++)
{
if(j>=a[i]) dp[i][j] = min(dp[i][j],dp[i-1][j-a[i]]);
if(j>=b[i]) dp[i][j] = min(dp[i][j],dp[i-1][j-b[i]]+1);
}
}
int ans = INF,mn = INF;
for(int i=0;i<=sum;i++)
{
if(dp[n][i]!=INF)
{
if(mn>abs(i-(sum-i)))
{
mn = abs(i-(sum-i));
ans = dp[n][i];
}
else if(mn==abs(i-(sum-i)))
{
ans = min(ans,dp[n][i]);
}
}
}
cout<<ans<<endl;
return 0;
}
DP好难啊