状压DP
先列一些状压DP的题目:
CF 377C Captains Mode
题意:告诉你有 \(n\) 个数,之后要进行 \(m\) 轮操作( \(m \le \min(n,20)\) ),每轮操作可能是以下两种形式中的一种:(1) Alice/Bob 中的一个人任意删掉一个剩余的数(也可以选择不删);(2) Alice/Bob 中的一个人任意取走某个剩余的数。假设Alice和Bob两人都以最优策略取数使得自己的总和-对方的总和尽可能大,那么 Alice的和 - Bob的和 会是多少。
Solution:
先观察到两个人的操作只会在最大的 \(m\) 个数中进行,于是可以用状压dp来做此题。再注意到可以认为两个人不会在某轮选择不删(因为总可以认为删掉了前 \(m\) 大数中剩下的最小的数),因此一个状态唯一对应着当前是第几轮操作。这样状压dp的复杂度就只有 \(O(m2^m)\) 了。
1 #include<bits/stdc++.h> 2 #define rep(i,a,n) for(int i=a;i<=n;i++) 3 #define per(i,a,n) for(int i=n;i>=a;i--) 4 #define pb push_back 5 #define mp make_pair 6 #define FI first 7 #define SE second 8 #define maxn 100 9 #define mod 1000000007 10 #define inf 0x3f3f3f3f 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pii; 14 typedef vector<int> vi; 15 typedef double db; 16 17 int a[maxn+5]; 18 char mode[25][5]; 19 int p[25]; 20 21 int dp[(1<<20)+5]; 22 int cnt[(1<<20)+5]; 23 24 int main() 25 { 26 rep(i,1,(1<<20)-1) cnt[i]=cnt[i>>1]+(i&1); 27 28 int n,m; scanf("%d",&n); 29 rep(i,1,n) scanf("%d",&a[i]); 30 sort(a+1,a+n+1,greater<int>()); 31 scanf("%d",&m); 32 rep(i,1,m) scanf("%s%d",mode[i],&p[i]); 33 rep(b,1,(1<<m)-1) 34 { 35 int i=m-cnt[b]+1; 36 dp[b]=p[i]==1?-inf:inf; 37 rep(j,1,m) if(b&(1<<j-1)) 38 { 39 if(p[i]==1) dp[b]=max(dp[b],dp[b^(1<<j-1)]+(mode[i][0]=='p'?a[j]:0)); 40 else dp[b]=min(dp[b],dp[b^(1<<j-1)]-(mode[i][0]=='p'?a[j]:0)); 41 } 42 } 43 printf("%d\n",dp[(1<<m)-1]); 44 return 0; 45 }
HDU 6006 Engineer Assignment
题意:告诉你有 \(n\) 个项目和 \(m\) 个人,每个项目需要一些能力(至多 \(3\) 个),每个人有一些能力(至多 \(2\) 个)。每个人最多被派去参加一个项目。问至多多少个项目可以完成(即集齐所需所有的能力)。
Solution:
预处理出第 \(i\) 个项目可以由哪些人完成,复杂度是 \(O(n 2^m)\),之后用状压dp,\(dp[i][st]\) 表示前 \(i\) 个项目由 \(st\) 这些人参加可以最多完成多少个项目。不过复杂度看起来是 \(O(T n 2^{2m})\),为什么能过我也不清楚。不清楚标算的时间复杂度。
1 #include<bits/stdc++.h> 2 #define rep(i,a,n) for(int i=a;i<=n;i++) 3 #define per(i,a,n) for(int i=n;i>=a;i--) 4 #define pb push_back 5 #define mp make_pair 6 #define FI first 7 #define SE second 8 #define maxn (1<<10) 9 #define mod 1000000007 10 #define inf (1ll<<60) 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pii; 14 typedef vector<int> vi; 15 typedef double db; 16 17 int dp[15][maxn+5]; 18 vi cost[15]; 19 20 int n,m; 21 int need[15][5],ncnt[15]; 22 int can[15][5],cnt[15]; 23 int tmp[105]; 24 25 void dfs(int dep,int st) 26 { 27 if(dep==0) 28 { 29 rep(i,1,n) 30 { 31 bool f=1; 32 rep(j,1,ncnt[i]) if(tmp[need[i][j]]==0) f=0; 33 if(f) cost[i].pb(st); 34 } 35 return; 36 } 37 dfs(dep-1,st); 38 rep(i,1,cnt[dep]) tmp[can[dep][i]]++; 39 dfs(dep-1,st|(1<<dep-1)); 40 rep(i,1,cnt[dep]) tmp[can[dep][i]]--; 41 } 42 43 int main() 44 { 45 int CAS; scanf("%d",&CAS); 46 rep(cas,1,CAS) 47 { 48 scanf("%d%d",&n,&m); 49 rep(i,1,n) 50 { 51 scanf("%d",&ncnt[i]); 52 rep(j,1,ncnt[i]) scanf("%d",&need[i][j]); 53 } 54 rep(i,1,m) 55 { 56 scanf("%d",&cnt[i]); 57 rep(j,1,cnt[i]) scanf("%d",&can[i][j]); 58 } 59 rep(i,1,n) cost[i].clear(); 60 dfs(m,0); 61 int M=1<<m; 62 int ans=0; 63 rep(i,1,n) 64 { 65 rep(st,0,M-1) 66 { 67 dp[i][st]=dp[i-1][st]; 68 for(auto d: cost[i]) if((st&d)==d) 69 { 70 dp[i][st]=max(dp[i][st],dp[i-1][st^d]+1); 71 ans=max(ans,dp[i][st]); 72 } 73 } 74 } 75 printf("Case #%d: %d\n",cas,ans); 76 } 77 return 0; 78 }
HDU 5838 Mountain

浙公网安备 33010602011771号