hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。
Posted 天道酬勤007
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。相关的知识,希望对你有一定的参考价值。
/** 题目:hdu6006 Engineer Assignment 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006 题意:已知n个工程,每个需要某些领域的专家。有m个工程师,每个人擅长一些领域。 一个工程师只能参加一个工程。一个工程可以多个工程师参加。 如果参加某个工程的工程师他们擅长的领域覆盖了该工程需要的领域。那么该工程可以执行。 问最多可以执行多少个工程。 思路: 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。 dp[i][s] = max(dp[i][s],dp[i-1][s‘]+1); s‘为s的子集,且f[i][s-s‘] = 1; */ #include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<vector> #include<cstring> using namespace std; typedef long long LL; const int N = 2e5+100; const int inf = 0x3f3f3f3f; vector<int> pro[12], eng[12]; map<int,int> mp; int f[11][1<<10]; int mv[12]; int rm[1<<20]; int n, m; int dp[2][1<<10]; void init() { mv[0] = 0; for(int i = 1; i <= m; i++){ int s = 0; for(int j = 0; j < eng[i].size(); j++){ s |= 1<<(mp[eng[i][j]]-1); } mv[i] = s; } int len = (1<<m); rm[0] = 0; for(int i = 1; i < len; i++){ rm[i] = 0; for(int j = 1; j <= m; j++){ if(i&(1<<(j-1))){ rm[i] |= mv[j]; } } } memset(f, 0, sizeof f); for(int i = 1; i <= n; i++){ int s1 = 0; for(int j = 0; j < pro[i].size(); j++){ if(mp[pro[i][j]]==0){ s1 = 0; break; } s1 |= 1<<(mp[pro[i][j]]-1); } if(s1==0) continue; for(int j = 1; j < len; j++){ if((rm[j]&s1)==s1){ f[i][j] = 1; } } } } int main() { int cas = 1, T; cin>>T; while(T--) { scanf("%d%d",&n,&m); int num, x; for(int i = 1; i <= n; i++){ scanf("%d",&num); pro[i].clear(); for(int j = 1; j <= num; j++){ scanf("%d",&x); pro[i].push_back(x); } } mp.clear(); int cnt = 1; for(int i = 1; i <= m; i++){ scanf("%d",&num); eng[i].clear(); for(int j = 1; j <= num; j++){ scanf("%d",&x); eng[i].push_back(x); if(mp[x]==0){ mp[x] = cnt++; } } } int len = (1<<m); init(); int now = 0; for(int i= 0; i < len; i++) dp[0][i] = 0; for(int i = 1; i <= n; i++){ now ^= 1; for(int s = 0; s < len; s++){ dp[now][s] = dp[now^1][s]; if(f[i][s]==0) continue; for(int s0 = s; s0; s0 = (s0-1)&s){ if(f[i][s0]) dp[now][s] = max(dp[now][s],dp[now^1][s-s0]+1); } } } printf("Case #%d: %d\n",cas++,dp[now][len-1]); } return 0; }
以上是关于hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6006 Engineer Assignment:状压dp
hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。
HDU2767Proving Equivalences[tarjan 缩点]