uva1252状压dp
题意:有n个物体,每个物体有m个特征,我心里想一个物品,你每次可以询问一个特征,然后我告诉你是否有这个特征,如果你采用最优策略,最少要询问几次才能保证猜到。
思路:要做的是鉴别出来我心里所想的那一个物品(0-1串),所以鉴别出来一个就可以了,而又不知道心里想的是哪一个,所以取需要询问次数最多的,取每个物品(0-1串)能被鉴别出来需要的次数中次数最大的,才能保证所有物品(0-1串)在该询问次数内都能被鉴别出来,注意题目中已说明采用的是最优策略,所以不需要考虑询问的是哪几个,只考虑次数就可以了,换句话说,选出询问次数最小的,当然前提是已经保证我考虑的最坏的情况(心里想的是需要询问次数最多的)。
求询问的次数,按询问的次数分阶段,询问1次是第一个阶段,询问2次是第二个阶段,……。在第i个阶段询问i次,这i次询问的特征是任意的,换句话说,询问0-1串中的元素个数是固定的(阶段),而询问哪i个位置是随意的(阶段中的决策)。
每次进入下一个阶段时,添加一个元素(特征),我想的物品可能有这个特征,也可能没有,设特征为k,max{d(s+{k},a+{k}),d(s+{k},a}+1。(考虑了最坏的情况)
k需要遍历,这里,已经考虑了最坏的情况,那么就可以只考虑次数了,取最小的次数。
#include<bits/stdc++.h> using namespace std; #define maxm 12 #define maxn 150 #define inf 0x3f3f3f3f int state[maxn]; int d[1<<maxm][1<<maxm]; int m,n; int dp(int s,int a) { if(d[s][a]!=inf)return d[s][a]; int c=0; for(int i=0;i<n;i++) if((state[i]&s)==a)c++; if(c<=1){d[s][a]=0;return 0;} for(int k=0;k<m;k++) { if(s&(1<<k))continue; d[s][a]=min(d[s][a],max(dp(s|1<<k,a|1<<k),dp(s|1<<k,a))+1); } return d[s][a]; } int main() { while(~scanf("%d%d",&m,&n),m,n) { char str[130]; memset(state,0,sizeof(state)); memset(d,inf,sizeof(d)); for(int i=0;i<n;i++) { scanf("%s",&str); for(int j=0;str[j];j++) if(str[j]=='1')state[i]|=(1<<j); } int ans=dp(0,0); printf("%d\n",ans); } }