状压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 }
View Code

 

 

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 }
View Code

 

HDU 5838 Mountain

posted @ 2018-12-19 18:50  YaoBIG  阅读(179)  评论(0)    收藏  举报