今天拿这道题目学习了一下状压dp
状压dp就是说把每个分状态用二进制来记录
比如这个题,我们先用map统计最多会有几种花
int n;
cin>>n;
for(int i=1;i<=n;i++){
int xx;cin>>xx;
while(xx--){
string x;
cin>>x;
if(!ma[x])ma[x]=++cnt;
v[i]|=1<<(ma[x]-1);
}
}
然后用i来表示所有的状态,对于每一个i,用i&v[j]进行比较,如果为0就说明这种情况有拿不到花的妹妹,不符合,需要break,然后用min更新答案即可;
for(int i=1;i<(1<<cnt);i++){
int res=__builtin_popcount(i);
if(res>cnt)continue;
int sum=0;
for(int j=1;j<=n;j++){
if(v[j]&i)sum++;
else break;
}
if(sum==n)ans=min(ans,res);
}
完整代码
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
map <string,ll> ma;
ll cnt;
ll v[22];
void solve(){
ma.clear();
cnt=0;
memset(v,0,sizeof(v));
ll n;
cin>>n;
for(ll i=1;i<=n;i++){
ll xx;cin>>xx;
while(xx--){
string x;
cin>>x;
if(!ma[x])ma[x]=++cnt;
v[i]|=1<<(ma[x]-1);//?
}
}
ll ans=cnt;
for(ll i=1;i<(1<<cnt);i++){
ll res=__builtin_popcount(i);
if(res>cnt)continue;
ll sum=0;
for(ll j=1;j<=n;j++){
if(v[j]&i)sum++;
else break;
}
if(sum==n)ans=min(ans,res);
}
cout<<ans<<endl;
}
int main(){
std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// freopen("sbcf.out","w",stdout);
ll T;cin>>T;
while(T--){
solve();
}
return 0;
}