题目链接: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
",ans);
}
return 0;
}