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 }
View Code

 

posted @ 2018-09-04 20:43  ccsu_dj辉  阅读(106)  评论(0编辑  收藏  举报