P1282 多米诺骨牌

中文题

 

想法:

观察到每次交换只是把上下两个数交换,故前i个骨牌上下两行数的总和是不变的,所以我们只需记录其中一行数字的和就可以知道差值了。这样状态就好表示了。

f[i][j]表示前i个数字,第一行的数字和是j时,最小的交换次数。初始值所有f[i][j]都是无穷大,f[1][a[1]]=0,f[1][b[1]]=1。(a[]和b[]分别表示第一行和第二行的数字)

转移时,枚举每一个可能的和,共有6*n个,考虑当前一个交不交换即可

 

最后去枚举第一行的和去找满足题意(差值最小)的最小交换次数

 

#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>
#include <sstream>
#include <iostream>
#include <cstring>

#define LL long long
#define ls nod<<1
#define rs (nod<<1)+1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define INF 0x3f3f3f3f

const double eps = 1e-10;
const int maxn = 1e3 + 10;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

int a[maxn],b[maxn];
int f[maxn][6*maxn];

int main() {
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    int tot = 0;
    for (int i = 1;i <= n;i++) {
        cin >> a[i] >> b[i];
        tot += (a[i] + b[i]);
    }
    for (int i = 0;i <= n;i++) {
        for (int j = 0;j <= 6*n;j++)
            f[i][j] = INF;
    }
    f[1][b[1]] = 1;
    f[1][a[1]] = 0;
    for (int i = 2;i <= n;i++) {
        for (int j = 0;j <= 6*n;j++) {
            if (j >= a[i])
                f[i][j] = min(f[i][j],f[i-1][j-a[i]]);
            if (j >= b[i])
                f[i][j] = min(f[i][j],f[i-1][j-b[i]]+1);
        }
    }
    int Minn = INF;
    int ans = INF;
    for (int i = 0;i <= tot;i++) {
        if (f[n][i] != INF) {
            if (abs(i-(tot-i)) < Minn) {
                Minn = abs(i-(tot-i));
                ans = f[n][i];
            }
            else if (abs(i-(tot-i)) == Minn)
                ans = min(ans,f[n][i]);
        }
    }
    cout << ans << endl;
    return 0;
}

 

posted @ 2020-03-10 22:18  _Ackerman  阅读(208)  评论(0编辑  收藏  举报