UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)
2017-04-21 11:02 tlnshuju 阅读(204) 评论(0) 编辑 收藏 举报题目链接:uva 1252
题意:
有n个长度为m的二进制串。每一个都是不同的。
为了把全部字符串区分开。你能够询问,每次能够问某位上是0还是1。
问最少提问次数,能够把全部字符串区分开来。
问最少提问次数,能够把全部字符串区分开来。
思路来源于:点击打开链接
思路:
m非常小。能够考虑状态压缩。
dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包括s2时最小须要的步数。
当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0;
不能区分则再询问一次,s1|=(1<<k),假设问某位为0。则s2不变,问某位为1,则s2|=(1<<k)。
递归下去就能找到答案了。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #define maxn 1005 #define MAXN 1000005 #define mod 100000000 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 typedef long long ll; using namespace std; int n,m,ans,tot,flag; char s[150][15]; int dp[1<<11][1<<11],mp[150]; int dfs(int s1,int s2) { if(dp[s1][s2]<INF) return dp[s1][s2]; int i,j,t=0; for(i=1;i<=n;i++) { if((mp[i]&s1)==s2) t++; } if(t<=1) { dp[s1][s2]=0; return 0; } int best=INF; for(i=0;i<m;i++) { if(s1&(1<<i)) continue ; best=min(best,max(dfs(s1|(1<<i),s2),dfs(s1|(1<<i),s2|(1<<i)))); } dp[s1][s2]=best+1; return best+1; } int main() { int i,j,t; while(~scanf("%d%d",&m,&n)) { if(m==0&&n==0) break ; for(i=1;i<=n;i++) { scanf("%s",s[i]); mp[i]=0; for(j=0;j<m;j++) { if(s[i][j]=='1') mp[i]|=(1<<j); } } memset(dp,0x3f,sizeof(dp)); ans=dfs(0,0); printf("%d\n",ans); } return 0; }