HDU 6006 Engineer Assignment:状压dp

时间:2023-03-09 12:52:34
HDU 6006 Engineer Assignment:状压dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006

题意:

  在Google中,有个n项目,m个专家。第i个项目涉及c[i]个领域,分别为a[i][0]...a[i][c[i]-1]。第i个专家精通d[i]个领域,分别为b[i][0]...b[i][d[i]-1]。

  如果要完成一个项目,则这个项目所涉及到的每一个领域都必须至少有一个精通该领域的专家。你作为director,可以任意分配专家,但一个专家只能去做一个项目。问你最多能够完成多少个项目。

题解:

  首先表示状态:

    当前考虑到第i个项目,专家的状态为state(每一位上0表示还没选,1表示已经选过了),在这之前最多能完成dp个项目。

    即:dp[i][state] = max num of finished pros

  如何转移:

    对于第i个项目,可以做或不做。

    (1)如果不做,则专家的状态state没有变化。

      dp[i+1][state] = max(dp[i+1][state], dp[i][state])

    (2)如果做,则首先要满足在剩下的专家中,有一些人能够完全覆盖到这个项目所涉及的领域。设这个项目可以选择的专家的方案为nex(每一位0代表不选,1代表选)。那么转移为:

      if(!(state&nex)) dp[i+1][state|nex] = max(dp[i+1][state|nex], dp[i][state] + 1)

  Tips:先预处理出每个项目合法的选专家的方案,存到vector中。

  求dp:先枚举第i个项目,再枚举此时的状态,做或不做两种情况分别处理。

AC Code:

 // dp[i][state] = max num of finished pros
// dp[i+1][state|nex] = max self and dp[i][state] + 1
// preprocess: the sequence of selected experts for each pros
// a state on exps is legal only if state_exp & state_now == 0 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#define MAX_N 15
#define MAX_C 5
#define MAX_A 105
#define MAX_S (1<<12) using namespace std; int n,m,t;
int cas=;
int ans;
int a[MAX_N][MAX_C];
int b[MAX_N][MAX_C];
int c[MAX_N];
int d[MAX_N];
bool pro[MAX_N][MAX_A];
bool exp[MAX_N][MAX_A];
int dp[MAX_N][MAX_S];
vector<int> transfer[MAX_N]; void read()
{
memset(pro,false,sizeof(pro));
memset(exp,false,sizeof(exp));
cin>>n>>m;
for(int i=;i<n;i++)
{
cin>>c[i];
for(int j=;j<c[i];j++)
{
cin>>a[i][j];
pro[i][a[i][j]]=true;
}
}
for(int i=;i<m;i++)
{
cin>>d[i];
for(int j=;j<d[i];j++)
{
cin>>b[i][j];
exp[i][b[i][j]]=true;
}
}
} bool check(int k,int state)
{
for(int i=;i<c[k];i++)
{
int ned=a[k][i];
bool flag=false;
for(int j=;j<m;j++)
{
if(((state>>j)&) && exp[j][ned])
{
flag=true;
break;
}
}
if(!flag) return false;
}
return true;
} void cal_exp()
{
for(int i=;i<n;i++)
{
transfer[i].clear();
for(int state=;state<(<<m);state++)
{
if(check(i,state)) transfer[i].push_back(state);
}
}
} void cal_dp()
{
memset(dp,,sizeof(dp));
ans=;
for(int i=;i<n;i++)
{
for(int state=;state<(<<m);state++)
{
dp[i+][state]=max(dp[i+][state],dp[i][state]);
for(int j=;j<transfer[i].size();j++)
{
int nex=transfer[i][j];
if(!(state&nex))
{
dp[i+][state|nex]=max(dp[i+][state|nex],dp[i][state]+);
}
}
}
}
} void solve()
{
cal_exp();
cal_dp();
for(int state=;state<(<<m);state++)
{
ans=max(ans,dp[n][state]);
}
} void print()
{
cout<<"Case #"<<(++cas)<<": "<<ans<<endl;
} int main()
{
cin>>t;
while(t--)
{
read();
solve();
print();
}
}