题目大意:有n个物品,每个物品有m个特征,每个物品的每个特征都可能有或没有,现在假定某个物品,通过询问某些特征来确定这个物品,问最多需要多少次就可以确定物品。
每次询问之后可能根据答案不同来采取不同的进一步询问的策略。
用d[S][S0]表示目前询问了S,得到的回答是S0(即那个物品在S中有S0这些特征),最少还需询问多少次。枚举下一次询问的特征完成递推。最终d[0][0]就是答案。S0显然是S的一个子集。下一次询问的特征不是S已有的特征。如果对于某个d[S][S0]只有一个物品满足,那么此时值为0,不需要更多的询问。
状态转移方程:
d[S][S0]=min { max(d[S|u][S0],d[S|u][S0|u]) }(u==(1<<k),S&u==0)
#include<stdio.h>
#include<stdlib.h>
int a[150];
int d[2100][2100];
char e[1010];
int main(void)
{
int i,j,u,p,q,n,m,sump,minp,OK,S,S0;
scanf("%d%d",&m,&n);
while((m!=0)||(n!=0))
{
for(i=1;i<=n;i++)
{
scanf("%s",e+1);
sump=0;
for(j=1;j<=m;j++)
{
sump=2*sump+e[j]-'0';
}
a[i]=sump;
}
p=(1<<m)-1;
for(S=p;S>=0;S--)
{
S0=S;
while(1)
{
sump=0;
OK=1;
for(i=1;i<=n;i++)
{
if((a[i]&S)==S0)
{
sump++;
if(sump>1)
{
OK=0;
break;
}
}
}
if(OK==1)
{
d[S][S0]=0;
}
else
{
minp=(1<<10);
for(i=1;i<=m;i++)
{
u=1<<(i-1);
if((u&S)==0)
{
q=d[S|u][S0]>d[S|u][S0|u]?d[S|u][S0]:d[S|u][S0|u];
minp=q<minp?q:minp;
}
}
d[S][S0]=minp+1;
}
if(S0==0)
{
break;
}
S0=(S0-1)&S;
}
}
printf("%d\n",d[0][0]);
scanf("%d%d",&m,&n);
}
return 0;
}