洛谷 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\n", ans);
return 0;
}