hdu6006 Engineer Assignment 状压dp

hdu6006 

题意:有 n 个工程, m 个人,每个工程需要 ci 个领域的知识,每个人精通 di 个领域。每个人只能去一个工程,问最多可完成多少个工程。

tags:数据范围小,状压

dp[i][j] 代表前 i 个工程在状态 j 的组合下,最多能完成多少个工程。

首先预处理出每个工程可由哪些人组合完成,用 0 ~ ((1<<m)-1)记录。这里有点麻烦。。

然后就是 dp 转移,在考虑到第 i 个工程时:

1】如不取这个工程,则 dp[i][j] = max(dp[i][j] , dp[i-1][j] ) ;

2】如取,则 dp[i][j] = max(dp[i][j] , dp[i-1][j^v]+1 ) ,   要求满足 j 包含 v 。

其实类似于背包。。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 200005;

int T, n, m, a[15][5], c[15], dp[15][1<<13], di, tmp;
vector<int > ve1[15], ve2[110];
void Init()
{
    rep(i,0,14) ve1[i].clear();
    rep(i,0,109) ve2[i].clear();
    mes(dp, 0);
}
int main()
{
    scanf("%d", &T);
    rep(cas,1,T)
    {
        scanf("%d%d", &n, &m);
        Init();
        rep(i,1,n)
        {
            scanf("%d", &c[i]);
            rep(j,1,c[i]) scanf("%d", &a[i][j]);
        }
        rep(i,0,m-1)
        {
            scanf("%d", &di);
            rep(j,1,di) scanf("%d", &tmp), ve2[tmp].PB(i);
        }

        rep(ci,1,n)   // Init
        {
            for(auto i : ve2[a[ci][1]])
            {
                if(c[ci]==1) { ve1[ci].PB( (1<<i) ); continue; }
                for(auto j : ve2[a[ci][2]])
                {
                    if(c[ci]==2) { ve1[ci].PB( (1<<i)|(1<<j) ); continue; }
                    for(auto l : ve2[a[ci][3]])
                        ve1[ci].PB( (1<<i)|(1<<j)|(1<<l) );
                }
            }
        }

        rep(i,1,n) rep(j,0,(1<<m)-1)
        {
            for(auto v : ve1[i])
            {
                if((j|v)==j)
                    dp[i][j] = max(dp[i][j], dp[i-1][j^v]+1);
            }
            dp[i][j] = max(dp[i][j], dp[i-1][j]);
        }

        int ans = 0;
        rep(j,0,(1<<m)-1)  ans = max(ans, dp[n][j]);
        printf("Case #%d: %d\n", cas, ans);
    }

    return 0;
}
posted @ 2017-09-19 18:02  v9fly  阅读(188)  评论(0编辑  收藏  举报