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);
    }
}

 

posted @ 2016-07-22 16:36  哲贤  阅读(300)  评论(0编辑  收藏  举报