题目大意:有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; }
时间: 2024-10-12 15:31:43