Engineer Assignment HDU - 6006 状压dp

Posted stupid_one

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Engineer Assignment HDU - 6006 状压dp相关的知识,希望对你有一定的参考价值。

http://acm.split.hdu.edu.cn/showproblem.php?pid=6006

比赛的时候写了一个暴力,存暴力,过了,还46ms

那个暴力的思路是,预处理can[i][j]表示第i个人能否胜任第j个项目,能胜任的条件就是它和这个项目有共同的需求。

然后暴力枚举每一个人去搭配哪一个项目,

技术分享
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define inff() freopen("data","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
typedef pair <int, int> pii;
const LL INF = 1e17;
const int inf = 0x3f3f3f3f;
const int maxn = 1e2 + 2;
vector<int> project[maxn], man[maxn];
int e[maxn][maxn], DFN;
bool can[12][12];
int n, m; // n_project, m_man
int has[12][maxn];
bool need[12][maxn];
int ans = 0;
void dfs(int cur) {
    if (cur == m + 1) {
        int t = 0;
        for (int i = 1; i <= n; ++i) {
            bool flag = true;
            for (int j = 0; j < project[i].size(); ++j) {
                if (!has[i][project[i][j]]) {
                    flag = false;
                    break;
                }
            }
            t += flag;
        }
        ans = max(ans, t);
        return;
    }
//    bool can = false;
    for (int i = 1; i <= n; ++i) {
        if (!can[cur][i]) continue;
        bool flag = false;
        for (int j = 0; j < man[cur].size(); ++j) {
            if (!need[i][man[cur][j]]) continue;
            if (has[i][man[cur][j]]) continue;
            flag = true;
            break;
        }
        if (!flag) continue;
        for (int j = 0; j < man[cur].size(); ++j) {
            has[i][man[cur][j]]++;
        }
        dfs(cur + 1);
        for (int j = 0; j < man[cur].size(); ++j) {
            has[i][man[cur][j]]--;
        }
    }
    dfs(cur + 1);
}
void work() {
    memset(can, false, sizeof can);
    memset(need, false, sizeof need);
    memset(has, false, sizeof has);
    scanf("%d%d", &n, &m);
    ++DFN;
    for (int i = 1; i <= n; ++i) { // project
        int c;
        scanf("%d", &c);
        project[i].clear();
        while (c--) {
            int val;
            scanf("%d", &val);
            project[i].push_back(val);
            e[i + m][val] = DFN;
            need[i][val] = true;
        }
    }
    for (int i = 1; i <= m; ++i) { // man
        int c;
        scanf("%d", &c);
        man[i].clear();
        while (c--) {
            int val;
            scanf("%d", &val);
            man[i].push_back(val);
            e[i][val] = DFN;
        }
    }
    for (int i = 1; i <= m; ++i) { // man
        for (int j = 1; j <= n; ++j) { // project
            for (int k = 1; k <= 100; ++k) { // major
                if (e[i][k] == DFN && e[j + m][k] == DFN) {
                    can[i][j] = true;
                    break;
                }
            }
        }
    }
    ans = 0;
    dfs(1);
    static int f = 0;
    printf("Case #%d: %d\n", ++f, ans);
}

int main()
{
    #ifdef LOCAL
    inff();
    #endif
    int T;scanf("%d",&T);
    while(T--)
    {
        work();
    }
    return 0;
}
View Code

 

正解是状压dp

其实是一个挺好想的dp

dp[i][1 << m]表示处理了前i个项目,状态是j的时候的最大完成数目。

首先预处理要完成第i个项目,状态k是否可行。然后类似于背包

给定状态s,去除子状态k后,就能完成第i项目了,所以dp[i][s] = max(dp[i][s], dp[i - ][s - k] + 1);

dp[i - 1][s - k] + 1表示用状态s - k去完成前i - 1个项目,能完成多少。

技术分享
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define inff() freopen("data","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
typedef pair <int, int> pii;
const LL INF = 1e17;
const int inf = 0x3f3f3f3f;
const int maxn = 1e2 + 2;
vector<int> project[maxn], man[maxn];
vector<int> state[maxn];
int solve[12][maxn], DFN;
int dp[12][1024 + 2];
void work() {
    int n, m; // n_project, m_man
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) { // project
        int c;
        scanf("%d", &c);
        project[i].clear();
        while (c--) {
            int val;
            scanf("%d", &val);
            project[i].push_back(val);
        }
    }
    for (int i = 1; i <= m; ++i) { // man
        int c;
        scanf("%d", &c);
        man[i].clear();
        while (c--) {
            int val;
            scanf("%d", &val);
            man[i].push_back(val);
        }
    }
    int en = (1 << m) - 1;
    for (int i = 1; i <= n; ++i) {
        state[i].clear();
        for (int j = 1; j <= en; ++j) {
            ++DFN;
            for (int k = 1; k <= m; ++k) {
                if (j & (1 << (k - 1))) {
                    for (int d = 0; d < man[k].size(); ++d) {
                        solve[i][man[k][d]] = DFN;
                    }
                }
            }
            bool flag = true;
            for (int d = 0; d < project[i].size(); ++d) {
                if (solve[i][project[i][d]] != DFN) {
                    flag = false;
                    break;
                }
            }
            if (flag) state[i].push_back(j);
        }
    }
//    for (int i = 1; i <= n; ++i) {
//        for (int j = 0; j < state[i].size(); ++j) {
//            printf("%d ", state[i][j]);
//        }
//        printf("\n");
//    }
    memset(dp, false, sizeof dp);
    for (int i = 1; i <= n; ++i) {
        for (int d = 1; d <= en; ++d) {
            dp[i][d] = dp[i - 1][d]; // 不做这个项目
            for (int k = 0; k < state[i].size(); ++k) {
                if ((d | state[i][k]) > d) continue;
                int res = d ^ state[i][k];
                dp[i][d] = max(dp[i][d], dp[i - 1][res] + 1);
            }
        }
    }
    int ans = 0;
    for (int i = 1; i <= en; ++i) ans = max(ans, dp[n][i]);
    static int f = 0;
    printf("Case #%d: %d\n", ++f, ans);
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
#endif
    int T;
    scanf("%d", &T);
    while(T--) {
        work();
    }
    return 0;
}
View Code

 

以上是关于Engineer Assignment HDU - 6006 状压dp的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6006 Engineer Assignment:状压dp

hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。

HDU 5289 Assignment

HDU 5289 Assignment

HDU 5289 Assignment(多校2015 RMQ 单调(双端)队列)

HDU2853 Assignment KM