poj 1717 Dominoes

转自http://hi.baidu.com/flabbyan/item/5383903d55235f647d034b70

题目大意:给成一组多米诺牌,每个多米诺牌由上面和下面两组数组成,现要求可以翻动颠倒上下,使得多米诺上边的点数和减去下边的点数和的绝对值最小

解题思路:

之前想的一个。。。。

用一个dp[i[0]表示第i个没颠倒的前i个牌和之差,dp[i][0]= dp[i-1][1] + (a - b) abs(dp[i-1][1] + (a-b) )< abs(dp[i-1][0] + (a-b)) 反之为dp[i-1][0] + (a - b)

dp[i][1]表示第i个上下翻转了的前j个牌之差。

然后用个record[i][0],record[i][1]记录翻转次数

 

是错的,不能保证最优子结构!!!!!!!

 

看了别人的解答。。。思路是这样的

dp[k] 表示多米诺前x个上下数之和为k时的最小翻动次数。

那么当处理第i个牌时

dp[k + i.a] = min(dp[k], dp[k+i.a])

dp[k+ i.b] = min(dp[k] + 1, dp[k+i.b])

每次推算时得记得重置dp[k]

最后,从总和的一半开始往前,往后各找到一个状态,找出这两个状态的最优的就是所求。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;

const int maxn = 12005;
const int inf = 0x7fffffff;


int dp[maxn], n;

int main()
{
	
	memset(dp, -1, sizeof(dp));
	dp[0] = 0;
	int s = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i++)
	{
		int a, b;
		scanf("%d %d", &a, &b);
		s += (a + b);
		for(int k = s; k >= 0; k--)
		{
			int tmp;
			if(dp[k] != -1)
			{
				tmp = dp[k];
				dp[k] = -1; //记得要重置,为下次推算做准备 
				if(dp[k + a] == -1 || dp[k + a] > tmp)
					dp[k + a] = tmp;
				if(dp[k + b] == -1 || dp[k + b] > tmp + 1)
					dp[k + b] = tmp + 1;
			}
		}
	}
	
	s /= 2;
	int i, j;
	for(i = s; i >= 0; i--)
	{
		if(dp[i] != -1)
			break;
	}
	for(j = s; j < maxn; j++)
	{
		if(dp[j] != -1)
			break;
	}
	
	printf("%d\n", dp[i] > dp[j] ? dp[j] : dp[i]);
	
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值