状压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 = 11, maxn = 130; int cnt[1<<maxm][1<<maxm], m, n, dp[1<<maxm][1<<maxm]; bitset<maxm> obj[maxn]; const int INF = 0x3fffffff; void preDeal() { for(int s = 0,M = 1<<m; s < M; s++){ fill(cnt[s],cnt[s]+s+1,0); fill(dp[s],dp[s]+s+1,INF); for(int i = 0; i < n; i++){ cnt[s][obj[i].to_ulong()&s]++; } } } int dfs(int s,int a) { if(cnt[s][a] <= 1) return 0; int &ans = dp[s][a]; if(ans<INF) return ans; for(int k = 0; k < m; k++){ if(s&1<<k) continue; int ns = s|1<<k; ans = min(ans,max(dfs(ns,a),dfs(ns,a|1<<k))+1); } return ans; } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d\n",&m,&n),m){ for(int i = 0; i < n; i++){ cin>>obj[i]; } preDeal(); printf("%d\n",dfs(0,0)); } return 0; }
时间: 2024-10-11 22:27:29