DP【洛谷P1282】

题目链接: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好难啊

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/83341210