• 题解 P1282 【多米诺骨牌】


    题目链接

    Solution 多米诺骨牌

    题目大意:给定(n)个牌,每个牌上下两部分各有一个权值,你可以将牌翻转使得上下权值交换。求在上下权值和差值绝对值最小的前提下的最小翻转次数

    动态规划-背包


    分析:

    其实这是一道货真价实的背包题

    我们要使得差值的绝对值最小,枚举一下上部分的权值和就可以了嘛

    问题变成了使得上部分权值和为给定的(w)的最小翻转次数

    (f[i][j])为前(i)个物品使上部分权值和为(j)的最小翻转次数

    显然(f[i][j] = egin{cases} f[i - 1][j - up[i]] \ f[i - 1][j - down[i]] + 1end{cases}),其中(up,down)分别表示一张牌上下部分的权值

    然后枚举一下,注意翻过了的情况,也就是说假设翻了(k)次,但是(n-k<k)的话我们实际上是只用翻(n-k)次的……

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 1024;
    int val[maxn][2],f[maxn][6666],n,mxsum,sum,ans1,ans2;
    int main(){
    	scanf("%d",&n);
    	for(int i = 1;i <= n;i++)
    		scanf("%d %d",&val[i][0],&val[i][1]),mxsum += max(val[i][0],val[i][1]),sum += val[i][0] + val[i][1];
    	memset(f,0x3f,sizeof(f));
    	f[0][0] = 0;
    	for(int i = 1;i <= n;i++)
    		for(int j = 0;j <= mxsum;j++){
    			if(j >= val[i][0])f[i][j] = min(f[i][j],f[i - 1][j - val[i][0]]);
    			if(j >= val[i][1])f[i][j] = min(f[i][j],f[i - 1][j - val[i][1]] + 1);
    		}
    	ans1 = 0x7fffffff;
    	for(int now = 0;now <= mxsum;now++)
    		if(f[n][now] <= n && (abs(sum - now * 2) < ans1 || (abs(sum - now * 2) == ans1 && min(f[n][now],n - f[n][now]) < ans2)))ans1 = abs(sum - now * 2),ans2 = min(f[n][now],n - f[n][now]);
    	printf("%d
    ",ans2);
    	return 0;
    } 
    
  • 相关阅读:
    动态调整iframe的高度
    Binary Tree Zigzag Level Order Traversal
    Leetcode Anagrams
    二叉树层次遍历串成单链表
    leetcode 4sum
    leetcode 二叉树系列
    编程之美2.3
    Decode Ways
    leetcode graycode
    leetcode editdistance
  • 原文地址:https://www.cnblogs.com/colazcy/p/11850933.html
Copyright © 2020-2023  润新知