HDU 6006 Engineer Assignment:状压dp
Posted Leohh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:
1 // dp[i][state] = max num of finished pros 2 // dp[i+1][state|nex] = max self and dp[i][state] + 1 3 // preprocess: the sequence of selected experts for each pros 4 // a state on exps is legal only if state_exp & state_now == 0 5 6 #include <iostream> 7 #include <stdio.h> 8 #include <string.h> 9 #include <vector> 10 #define MAX_N 15 11 #define MAX_C 5 12 #define MAX_A 105 13 #define MAX_S (1<<12) 14 15 using namespace std; 16 17 int n,m,t; 18 int cas=0; 19 int ans; 20 int a[MAX_N][MAX_C]; 21 int b[MAX_N][MAX_C]; 22 int c[MAX_N]; 23 int d[MAX_N]; 24 bool pro[MAX_N][MAX_A]; 25 bool exp[MAX_N][MAX_A]; 26 int dp[MAX_N][MAX_S]; 27 vector<int> transfer[MAX_N]; 28 29 void read() 30 { 31 memset(pro,false,sizeof(pro)); 32 memset(exp,false,sizeof(exp)); 33 cin>>n>>m; 34 for(int i=0;i<n;i++) 35 { 36 cin>>c[i]; 37 for(int j=0;j<c[i];j++) 38 { 39 cin>>a[i][j]; 40 pro[i][a[i][j]]=true; 41 } 42 } 43 for(int i=0;i<m;i++) 44 { 45 cin>>d[i]; 46 for(int j=0;j<d[i];j++) 47 { 48 cin>>b[i][j]; 49 exp[i][b[i][j]]=true; 50 } 51 } 52 } 53 54 bool check(int k,int state) 55 { 56 for(int i=0;i<c[k];i++) 57 { 58 int ned=a[k][i]; 59 bool flag=false; 60 for(int j=0;j<m;j++) 61 { 62 if(((state>>j)&1) && exp[j][ned]) 63 { 64 flag=true; 65 break; 66 } 67 } 68 if(!flag) return false; 69 } 70 return true; 71 } 72 73 void cal_exp() 74 { 75 for(int i=0;i<n;i++) 76 { 77 transfer[i].clear(); 78 for(int state=0;state<(1<<m);state++) 79 { 80 if(check(i,state)) transfer[i].push_back(state); 81 } 82 } 83 } 84 85 void cal_dp() 86 { 87 memset(dp,0,sizeof(dp)); 88 ans=0; 89 for(int i=0;i<n;i++) 90 { 91 for(int state=0;state<(1<<m);state++) 92 { 93 dp[i+1][state]=max(dp[i+1][state],dp[i][state]); 94 for(int j=0;j<transfer[i].size();j++) 95 { 96 int nex=transfer[i][j]; 97 if(!(state&nex)) 98 { 99 dp[i+1][state|nex]=max(dp[i+1][state|nex],dp[i][state]+1); 100 } 101 } 102 } 103 } 104 } 105 106 void solve() 107 { 108 cal_exp(); 109 cal_dp(); 110 for(int state=0;state<(1<<m);state++) 111 { 112 ans=max(ans,dp[n][state]); 113 } 114 } 115 116 void print() 117 { 118 cout<<"Case #"<<(++cas)<<": "<<ans<<endl; 119 } 120 121 int main() 122 { 123 cin>>t; 124 while(t--) 125 { 126 read(); 127 solve(); 128 print(); 129 } 130 }
以上是关于HDU 6006 Engineer Assignment:状压dp的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6006 Engineer Assignment:状压dp
hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。
HDU2767Proving Equivalences[tarjan 缩点]