链接:https://www.luogu.org/problem/P1282 思路: 考虑到$a,b$极小,可以采用背包做法。 由于一张牌上下的点数和是不变的,所以若知道当前某一行的个数,则可以知道另外一行。 设$f[i][j]$表
链接:https://www.luogu.org/problem/P1282
思路:
考虑到$a,b$极小,可以采用背包做法。
由于一张牌上下的点数和是不变的,所以若知道当前某一行的个数,则可以知道另外一行。
设$f[i][j]$表示前$i$张牌,第一行点数和为$j$的最小翻转次数。
最后枚举第一行的和即可。
注意背包前所有状态(除了初始化)要设为极大值。
代码:
#include <bits/stdc++.h> const int INF = 1 << 30; const int MAXN = 1050; using namespace std; int n, sum, res, Minx = INF, ans = INF, a[MAXN], b[MAXN], f[MAXN][MAXN * 6 + 5]; int main() { cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i] >> b[i]; sum += a[i] + b[i]; } for(int i = 1; i <= n; i++) { for(int j = 0; j <= 6 * n; j++) f[i][j] = INF; } f[1][a[1]] = 0; f[1][b[1]] = 1; for(int i = 2; i <= n; i++) { for(int j = 0; j <= 6 * n; j++) { if(j - a[i] >= 0) f[i][j] = min(f[i][j], f[i - 1][j - a[i]]); if(j - b[i] >= 0) f[i][j] = min(f[i][j], f[i - 1][j - b[i]] + 1); } } for(int i = 0; i <= sum; i++) { if(f[n][i] == INF) continue; int res = abs(i - (sum - i)); if(res < Minx) { Minx = res; ans = f[n][i]; } if(res == Minx) ans = min(ans, f[n][i]); } cout << ans << endl; return 0; }