题目大意:有n个东西,m个特征,每个东西都有这m个特征,对于每一特征,要么为0,要么为1,现在你可以询问每一个特征,然后有人告诉你0 or 1,你根据这些来判断是哪个东西,你并不知道答案,现在要使询问次数最少,输出这个最少次数。
思路:肯定是记忆化搜索,枚举还没有问过的每个问题,然后有相应的答案,设d[ ques ][ ans ] 为已经问了状态为ques的问题,这些问题的答案是ans的最小次数,则状态转移方程为:d[ ques ][ ans ] = min(max(d[ ques|(1<<i) ][ ans|(1<<i) ,d[ ques|(1<<i)][ ans ]))。再用一个数组来记录当前这个状态下还剩下哪几个东西。
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int INF = 0x0fffffff ; const int MAXN = 133 ; char stat[MAXN][13]; int d[1<<12][1<<12]; int m,n; int dp(int ques,int ans,vector<int> v) { if(d[ques][ans]!=-1) return d[ques][ans]; if(v.size()<=1) return d[ques][ans]= 0; d[ques][ans] = INF; vector <int> v1; vector <int> v2; for(int i = 0;i<m;i++) { if(ques&(1<<i)) continue; v1.clear(); v2.clear(); for(int j = 0;j<v.size();j++) { int x = v[j]; if(stat[x][i]=='1') v1.push_back(x); else v2.push_back(x); } d[ques][ans] = min(d[ques][ans],max(dp(ques|(1<<i),ans|(1<<i),v1),dp(ques|(1<<i),ans,v2))+1); } return d[ques][ans]; } int main() { while(~scanf("%d%d",&m,&n)&&(n+m)) { for(int i = 0;i<n;i++) scanf("%s",stat[i]); vector <int> v; for(int i =0;i<n;i++) v.push_back(i); memset(d,-1,sizeof(d)); printf("%d\n",dp(0,0,v)); } return 0; } /* 3 4 001 011 100 000 */