题面
有n(n≤128)个物体,m(m≤11)个特征。每个物体用一个m位01串表示,表示每个特征是具备还是不具备。
我在心里想一个物体(一定是这n个物体之一),由你来猜。
你每次可以询问一个特征,然后我会告诉你:我心里的物体是否具备这个特征。
当你确定答案之后,就把答案告诉我(告知答案不算“询问”)。
如果你采用最优策略,最少需要询问几次能保证猜到?
例如,有两个物体:1100和0110,只要询问特征1或者特征3,就能保证猜到。
分析
dp[k][c]存状态,其中k表示已经询问了的特征,c表示心里所想物体已经确定具备的特征,存的是还需要询问的次数。
每一次选择一个还没有被确定的特征i,去更新的dp[k|i][c|i]=max(dp[k|i][c|i],dp[k|i][c])+1
状态太多,用记忆化搜索。边界是这些特征能确定的物品数量,如果<=1,就应该返回了
代码
#include<bits/stdc++.h> using namespace std; #define N 12 #define INF 0x3f3f3f3f int n,m,w[N*N],dp[1<<N][1<<N]; char s[N*N]; inline void init() { memset(w,0,sizeof(w)); memset(dp,0x3f,sizeof(dp)); } inline int dfs(int k,int c) { int &ans=dp[k][c]; if(ans!=INF)return ans; int cnt=0; for(int i=1;i<=n;i++) if((k&w[i])==c)cnt++; if(cnt<=1) {dp[k][c]=0;return 0;} for(int i=1;i<=m;i++) if((k&(1<<i-1))==0) ans=min(ans,max(dfs(k|(1<<i-1),c|(1<<i-1)),dfs(k|(1<<i-1),c))+1); return ans; } int main() { while(scanf("%d%d",&m,&n)&&m) { init(); for(int i=1;i<=n;i++) { scanf("%s",s); for(int j=1;j<=m;j++) if(s[j-1]=='1')w[i]|=(1<<j-1); } printf("%d ",dfs(0,0)); } return 0; }