poj 1717 Dominoes

来源:互联网 发布:网络直播平台搭建 编辑:程序博客网 时间:2024/05/01 07:09

转自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;}