欢迎来到lbxer的博客
lbxer
lbxer
晓看天色暮看云,行也思君,坐也思君

csp赛前刷题 状压篇 [POI2004]PRZ

P5911 [POI2004]PRZ

刷题同时,总结一下状压。

在状压中发挥重要作用:位运算(&,|,^,~)常见的应用:

下面是由江苏省淮阴中学薛志坚整理的一些常见操作:

 

对于状压,什么是状压:一般基础的状压就是将一行状态,压成一个二进制数形式。最近做的题,基本涉及对于选不选的问题。

回到本题

状压 dpdp。把每一个人选不选压为二进制。

如 88 个人中选了 1,31,3 和 44 就可以表示为 0000110100001101

C[i]C[i] 表示当 ii 这些人为一队时的总重量。T[i]T[i] 表示当 ii 这些人为一队时里面最慢的那个人要的时间。

状态转移方程:

 

if(C[i ^ j] <= w) f[i] = min(f[i], f[j] + T[i ^ j]);

上代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define inf 2147483647
#define MAXN (1 << 16) + 1
using namespace std;
int w, n, c[17], t[17];
int T[MAXN], C[MAXN], f[MAXN];

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

int main() {
    cin >> w >> n;;
    for (int i = 1; i <= n; ++i) cin >> t[i] >> c[i];
    for (int i = 0; i < (1 << n); ++i) {
        int d = i, cnt = 0;
        while (d) {
            ++cnt;
            if (d & 1) {
                C[i] += c[cnt];
                T[i] = max(T[i], t[cnt]);
            }
            d >>= 1;
        }
        f[i] = inf;
    }
    f[0] = 0;
    for (int i = 0; i < (1 << n); ++i) {
        for (int j = i; j >= 0; j = i & (j - 1)) {
            if (C[i ^ j] <= w) f[i] = min(f[i], f[j] + T[i ^ j]);
            if (j == 0) break;
        }
    }
    printf("%d\n", f[(1 << n) - 1]);
    return 0;
}

 

状压 dpdp。把每一个人选不选压为二进制。

如 88 个人中选了 1,31,3 和 44 就可以表示为 0000110100001101

C[i]C[i] 表示当 ii 这些人为一队时的总重量。T[i]T[i] 表示当 ii 这些人为一队时里面最慢的那个人要的时间。

状态转移方程:

if(C[i ^ j] <= w) f[i] = min(f[i], f[j] + T[i ^ j]);

posted @ 2020-10-15 14:13  雷痕小祥  阅读(261)  评论(0编辑  收藏  举报
Live2D