zoukankan      html  css  js  c++  java
  • 洛谷 [P1282] 多米诺骨牌

    这道题是一道背包问题,考虑一个背包,

    显然如果我们直接设dp[i]表示前i个使差值最小所需的最少翻转次数,是具有后效性的。

    所以我们将直接求最值,改为求某个值是否可行,这种求最值转变为求可行性的思想是非常实用的。
    状态 dp[i][j]表示使用前i个物品修改得到差值j的最小步数。
    第一步求出原来两个数组的总和的差值Delta(DD)是多少。

    第二步进行背包DP,每个物品的质量为:t=a[i]-b[i],枚举改或不改,这样做相当于是我们企图去弥补两个数组和的差异Delta。

    第三步就是找到一个能够构造出来的最小的Delta就行啦。,对负数的处理可以直接加上一个很大的N。
    初始化dp[0][DD]=0,其余全为INF
    转移方程 dp[i][j]=min(dp[i][j],dp[i-1][j]);
    dp[i][j]=min(dp[i][j],dp[i-1][j-2*t]+1);

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cstdlib>
    using namespace std;
    const int MAXN=1005,MAXM=MAXN*5;
    int init(){
    	int rv=0,fh=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') fh=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		rv=(rv<<1)+(rv<<3)+c-'0';
    		c=getchar();
    	}
    	return rv*fh;
    }
    int dp[MAXN][(MAXM<<1)+MAXN];
    int main(){
    	freopen("in.txt","r",stdin);
    	int n=init();
    	memset(dp,0x3f,sizeof(dp));
    	dp[0][MAXM]=0;
    	for(int i=1;i<=n;i++){
    		int a=init(),b=init();
    		int t=a-b;
    		for(int j=-MAXM;j<=MAXM;j++){
    			dp[i][j+MAXM]=min(dp[i][j+MAXM],dp[i-1][j-t+MAXM]);
    			dp[i][j+MAXM]=min(dp[i][j+MAXM],dp[i-1][j+t+MAXM]+1);
    		}
    	}
    	for(int i=0;i<=MAXM;i++){
    		if(dp[n][MAXM-i]<=2005){
    			printf("%d
    ",min(dp[n][MAXM-i],dp[n][MAXM+i]));
    			return 0;
    		}
    		if(dp[n][MAXM+i]<=2005){
    			printf("%d
    ",min(dp[n][MAXM-i],dp[n][MAXM+i]));
    			return 0;
    		}
    	}
    	fclose(stdin);
    	return 0;
    }
    
    
  • 相关阅读:
    BZOJ 1191 HNOI2006 超级英雄hero
    BZOJ 2442 Usaco2011 Open 修建草坪
    BZOJ 1812 IOI 2005 riv
    OJ 1159 holiday
    BZOJ 1491 NOI 2007 社交网络
    NOIP2014 D1 T3
    BZOJ 2423 HAOI 2010 最长公共子序列
    LCA模板
    NOIP 2015 D1T2信息传递
    数据结构
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/7868265.html
Copyright © 2011-2022 走看看