UVA - 1252 Twenty Questions (状压dp)

时间:2023-03-10 03:16:39
UVA - 1252 Twenty Questions (状压dp)

状压dp,用s表示已经询问过的特征,a表示W具有的特征。

当满足条件的物体只有一个的时候就不用再猜测了。对于满足条件的物体个数可以预处理出来

转移的时候应该枚举询问的k,因为实际上要猜的物品是不确定的,要么k是W所具有的,要么k不是W所具有的,

要保证能猜到那么就应该取最坏情况下的最小值,所以有转移方程:dp[s][a] = min(max(dp[s|1<<k][a],dp[s|1<<k][a|1<<k]))。

询问特征可能转移到一个非法的状态,即满足条件的物品数量为0个。根据转移方程应该返回0。

#include<bits/stdc++.h>
using namespace std; const int maxm = , maxn = ; int cnt[<<maxm][<<maxm], m, n, dp[<<maxm][<<maxm]; bitset<maxm> obj[maxn];
const int INF = 0x3fffffff; void preDeal()
{
for(int s = ,M = <<m; s < M; s++){
fill(cnt[s],cnt[s]+s+,);
fill(dp[s],dp[s]+s+,INF);
for(int i = ; i < n; i++){
cnt[s][obj[i].to_ulong()&s]++;
}
}
} int dfs(int s,int a)
{
if(cnt[s][a] <= ) return ;
int &ans = dp[s][a];
if(ans<INF) return ans;
for(int k = ; k < m; k++){
if(s&<<k) continue;
int ns = s|<<k;
ans = min(ans,max(dfs(ns,a),dfs(ns,a|<<k))+);
}
return ans;
} int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d\n",&m,&n),m){
for(int i = ; i < n; i++){
cin>>obj[i];
}
preDeal();
printf("%d\n",dfs(,));
}
return ;
}