HDU - 6006 Engineer Assignment(状压dp)

题目链接

题意:有 n n n个任务,完成这些任务需要一些领域的知识。有 m m m个工程师,每个工程师都有一些自己会的领域。每个工程师只能选择一个任务,若参与这项任务的工程师具备了完成所需的所有知识,这项任务则被完成。问最多能完成几个任务。
题解:题目给的n和m都很小,所以想到了状压 d p dp dp去实现。 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i个任务在使用工程师 j j j状态下最多能完成的任务个数。在维护 d p dp dp状态之前,要额外跑一遍来确定能完成第 i i i个任务的方案,用于最后的状态转移。

#include <bits/stdc++.h>
using namespace std;

#define endl "\n"

int dp[15][1 << 11], c[15], d[15], a[15][15], b[15][15], vis[150];
int n, m, cas;
vector<int> G[15];

void solve() {
    memset(dp, 0, sizeof(dp));
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> c[i];
        G[i].clear();
        for (int j = 1; j <= c[i]; ++j) cin >> a[i][j];
    }
    for (int i = 1; i <= m; ++i) {
        cin >> d[i];
        for (int j = 1; j <= d[i]; ++j) cin >> b[i][j];
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < 1 << m; ++j) {
            memset(vis, 0, sizeof(vis));
            for (int k = 0; k < m; ++k) {
                if ((1 << k) & j) {
                    for (int q = 1; q <= d[k + 1]; ++q) {
                        vis[b[k + 1][q]] = 1;
                    }
                }
            }
            for (int q = 1; q <= c[i]; ++q) {
                if (!vis[a[i][q]]) break;
                if (q == c[i]) G[i].push_back(j);
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < 1 << m; ++j) {
            dp[i][j] = dp[i - 1][j];//注意这步状态转移
            for (auto v : G[i]) {
                if ((v & j) != v) continue;
                dp[i][j] = max(dp[i - 1][j - v] + 1, dp[i][j]);
            }
        }
    }
    cout << "Case #" << ++cas << ": " << dp[n][(1 << m) - 1] << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int _T;
    cin >> _T;
    while (_T--) solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值