洛谷 P1282 多米诺骨牌 (01背包)

题目链接:https://www.luogu.com.cn/problem/P1282

每个骨牌都有翻转或不翻转两种状态,体积分别为 (a[i]-b[i])(b[i]-a[i]) 可以为负,代价分别为 (0)(1),最终要求使体积绝对值最小的代价最小

(dp[i][j]) 表示前 (i) 个骨牌,体积为 (j) 时的最小代价,(01) 背包转移即可,注意负坐标要偏移

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1010;
const int INF = 0x3f3f3f3f;

int n;
int a[maxn], b[maxn]; 
int dp[maxn][30*maxn];

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read();
	for(int i = 1 ; i <= n ; ++i) a[i] = read(), b[i] = read();
	
	memset(dp, 0x3f, sizeof(dp)); 
	
	dp[0][0+7000] = 0;
	for(int i = 1 ; i <= n ; ++i){
		for(int j = 7000 ; j >= -7000 ; --j){
			if(dp[i-1][j-(a[i]-b[i])+7000] != INF) dp[i][j+7000] = min(dp[i][j+7000], dp[i-1][j-(a[i]-b[i])+7000]); // 不转 
			if(dp[i-1][j-(b[i]-a[i])+7000] != INF) dp[i][j+7000] = min(dp[i][j+7000], dp[i-1][j-(b[i]-a[i])+7000] + 1); // 转 
		}
	}
	
	int ans = INF; int flag = 0;
	for(int i = 0 ; i <= 6000 ; ++i){
		if(dp[n][i+7000] != INF) {
			ans = min(ans, dp[n][i+7000]);
			flag = 1;
		}
		if(dp[n][-i+7000] != INF) {
			ans = min(ans, dp[n][-i+7000]);
			flag = 1;
			break;
		}
		if(flag) break;
	}
	printf("%d
", ans);
	
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/15063946.html