UVA - 1252 Twenty Questions(状压DP)
题目链接:https://vjudge.net/problem/UVA-1252
题意:有n件物品,每件物品有m个特征,可以对特征进行询问,
询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来
(n个物品的特征都互不相同)最小需要多少次询问?
题目分析:定义dp(s,a)表示询问了的特征集合为s,
物体含有特征集合a中的所有特征,但不含特征集合 s^a 中的所有特征时还需的最少询问次数。
状态转移方程为dp(s,a)=min(max(dp(s|(1<<k),a|(1<<k)),dp(s|(1<<k),a))+1)。
用记忆化搜索的形式实现即可。
当这样的物体只有一个或一个没有时,便可区分出所有的物品,此时dp(s,a)=0。
AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int INF=1<<30; 6 const int maxn=1<<11; 7 int st[130],d[maxn][maxn]; 8 int m,n; 9 char ch[13]; 10 int getval(){ 11 int res=0; 12 for(int i=0;i<strlen(ch);i++) 13 if(ch[i]=='1') 14 res=res|(1<<i); 15 return res; 16 } 17 int dp(int s,int a){ 18 if(d[s][a]!=INF) return d[s][a]; 19 int num=0; 20 for(int i=0;i<n;i++) 21 if((st[i]&s)==a) num++; 22 if(num<=1) return d[s][a]=0; 23 int &ans=d[s][a]; 24 for(int i=0;i<m;i++){ 25 if(s&(1<<i)) continue; //同一个特征不需要问两遍,s集合存储不一样的特征 26 ans=min(ans,max(dp(s|(1<<i),a),dp(s|(1<<i),a|(1<<i)))+1); 27 } 28 return ans; 29 } 30 int main(){ 31 while(scanf("%d%d",&m,&n)&&m&&n){ 32 for(int i=0;i<n;i++){ 33 scanf("%s",ch); 34 st[i]=getval(); 35 } 36 for(int i=0;i<maxn;i++) 37 for(int j=0;j<maxn;j++) 38 d[i][j]=INF; 39 printf("%d\n",dp(0,0)); 40 } 41 }