枚举子集
二进制枚举子集下面代码就是枚举的s的子集(二进制状态压缩)
for(int i=s;i;i=(i-1)&s)
{
//i表示的就是s的子集
}
枚举所有子集的子集的时间复杂度
比如一个有n个元素构成的集合,子集的数量是
2
n
2^n
2n,现要求枚举所有子集的子集。
一个有k个元素构成的集合,子集的数量是
2
k
2^k
2k
考虑
n
n
n个元素构成的集合子集:
元素个数是
0
0
0的集合个数是
C
n
0
C_n^0
Cn0
元素个数是
1
1
1的集合个数是
C
n
1
C_n^1
Cn1
…
\dots
…
于是有以下等式
C
n
0
×
2
0
+
C
n
1
×
2
n
+
⋯
+
C
n
n
×
2
n
=
(
1
+
2
)
n
=
3
n
C_n^0×2^0+C_n^1×2^n+\dots+C_n^n×2^n=(1+2)^n=3^n
Cn0×20+Cn1×2n+⋯+Cnn×2n=(1+2)n=3n
由此最终需要枚举 3 n 3^n 3n个状态,时间复杂度为 Θ ( 3 n ) \Theta(3^n) Θ(3n)
Close Group
首先暴力预处理出所有满足题意的连通块,连通块中的点两两之间有直接边。 Θ ( n 2 + 2 n ) \Theta(n^2+2^n) Θ(n2+2n)
状态压缩dp
状态表式:
f
i
f_i
fi表示选择
i
i
i这些点构成的最少数量的团
状态计算:枚举
i
i
i状态的子集
j
j
j,于是有
f
i
=
m
i
n
(
f
i
,
f
j
+
f
i
⊕
j
)
f_i=min(f_i,f_j+f_{i\oplus j})
fi=min(fi,fj+fi⊕j)
时间复杂度:枚举所有状态的子集即上述证明
Θ
(
3
n
)
\Theta(3^n)
Θ(3n)
时间复杂度 Θ ( n 2 + 2 n + 3 n ) \Theta(n^2+2^n+3^n) Θ(n2+2n+3n)
3
18
=
387420489
3^{18}=387 420 489
318=387420489差不多能过,谁让状态压缩就是那么玄学呢
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=20;
bool ok[1<<N];
int g[N][N];
int dp[1<<N];
int main()
{
IO;
int T=1;
//cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
while(m--)
{
int a,b;
cin>>a>>b;
--a,--b;
g[a][b]=g[b][a]=1;
}
for(int i=0;i<1<<n;i++)
{
vector<int> t;
for(int j=0;j<n;j++)
if(i>>j&1) t.push_back(j);
ok[i]=1;
for(int j=0;j<t.size();j++)
for(int k=j+1;k<t.size();k++)
if(!g[t[j]][t[k]]) ok[i]=0;
}
for(int i=0;i<1<<n;i++) dp[i]=n+1;
dp[0]=0;
for(int i=1;i<1<<n;i++)
{
if(ok[i]) dp[i]=1;
for(int j=i;j;j=(j-1)&i)
dp[i]=min(dp[i],dp[j]+dp[j^i]);
}
cout<<dp[(1<<n)-1]<<'\n';
}
return 0;
}
E - Or Plus Max
对于K的子集一定满足
i
o
r
j
≤
K
i\ or\ j\leq K
i or j≤K
枚举子集,记录子集的最大值和次大值,相加即可
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=500010;
int a[N];
int mx[N],f[N];
int main()
{
IO;
int T=1;
//cin>>T;
for(int ca=1;ca<=T;ca++)
{
int n;
cin>>n;
for(int i=0;i<1<<n;i++)
{
cin>>a[i];
mx[i]=a[0];
}
for(int i=0;i<1<<n;i++)
for(int j=i;j;j=(j-1)&i)
{
f[i]=max(f[i],a[j]+mx[i]);
mx[i]=max(mx[i],a[j]);
}
for(int i=1;i<1<<n;i++)
{
f[i]=max(f[i-1],f[i]);
cout<<f[i]<<'\n';
}
}
return 0;
}