1. 程式人生 > >hdu6006 Engineer Assignment 狀態dp 定義dp[i][s]表示前i個工程狀態為s可以執行的最大工程數。s表示前i個工人選走了s狀態的工程師。

hdu6006 Engineer Assignment 狀態dp 定義dp[i][s]表示前i個工程狀態為s可以執行的最大工程數。s表示前i個工人選走了s狀態的工程師。

namespace algo acm names .cn num stream assign target

/**
題目: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狀態的工程師。