POJ2923--Relocation(01背包+状压dp)

果然对状压DP,我根本就不懂=。=

/**************************************************
Problem: 2923		User: G_lory
Memory: 720K		Time: 157MS
Language: G++		Result: Accepted
**************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int MAXN = 1 << 11;
const int INF = 0x5f5f5f5f;

int n, c1, c2;
int w[12];
int dp[MAXN];
int vis[MAXN];
int bag[MAXN];


bool ok(int st)
{
    memset(vis, 0, sizeof vis);
    vis[0] = 1;
    int sum = 0;
    for (int i = 0; i < n; ++i)
    {
        if ((1 << i) & st)//if (i & n)
        {
            sum += w[i];
            if (sum > c1 + c2) return false;// 很好理解,如果比两个车装的物体和还大,不可能一次装完
            for (int j = c1; j >= w[i]; --j)
            {
                if (vis[j - w[i]])  // 对n这个状态含有的物体做01背包,
                    vis[j] = 1;     // vis[j]=1表示物体可以刚好组成j,且j可以c1被装下
            }
        }
    }

    for (int i = 0; i <= c1; ++i)   // 就是看sum能否被两车一次装下
        if (sum - i <= c2 && vis[i]) return true;
    return false;
}


int main()
{
    int t;
    scanf("%d", &t);
    for (int cas = 1; cas <= t; ++cas)
    {
        scanf("%d%d%d", &n, &c1, &c2);

        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &w[i]);
        }

        int st = (1 << n) - 1;
        int cnt = 0;

        for (int i = 1; i <= st; ++i)
        {
            if (ok(i))
            {
                bag[cnt++] = i;
            }
        }

        for (int i = 1; i <= st; ++i) dp[i] = INF;
        dp[0] = 0;

        for (int i = 0; i < cnt; ++i)
        {
            for (int j = st; j >= 0; --j)
            {
                if (dp[j] != INF && (j & bag[i]) == 0)
                {
                    dp[j | bag[i]] = min(dp[j | bag[i]], dp[j] + 1);
                }
            }
        }

        printf("Scenario #%d:
%d

", cas, dp[st]);

    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/wenruo/p/4906386.html