UVALive 4643 Twenty Questions

题目大意:有n个东西,m个特征,每个东西都有这m个特征,对于每一特征,要么为0,要么为1,现在你可以询问每一个特征,然后有人告诉你0 or 1,你根据这些来判断是哪个东西,你并不知道答案,现在要使询问次数最少,输出这个最少次数。

思路:肯定是记忆化搜索,枚举还没有问过的每个问题,然后有相应的答案,设d[ ques ][ ans ] 为已经问了状态为ques的问题,这些问题的答案是ans的最小次数,则状态转移方程为:d[ ques ][ ans ] = min(max(d[ ques|(1<<i) ][ ans|(1<<i) ,d[ ques|(1<<i)][ ans ]))。再用一个数组来记录当前这个状态下还剩下哪几个东西。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int INF = 0x0fffffff ;

const int MAXN = 133 ;

char stat[MAXN][13];

int d[1<<12][1<<12];

int m,n;

int dp(int ques,int ans,vector<int> v)
{
    if(d[ques][ans]!=-1) return d[ques][ans];
    if(v.size()<=1) return d[ques][ans]= 0;
    d[ques][ans] = INF;
    vector <int> v1;
    vector <int> v2;
    for(int i = 0;i<m;i++)
    {
        if(ques&(1<<i)) continue;
        v1.clear();
        v2.clear();
        for(int j = 0;j<v.size();j++)
        {
            int x = v[j];
            if(stat[x][i]=='1') v1.push_back(x);
            else v2.push_back(x);
        }
        d[ques][ans] = min(d[ques][ans],max(dp(ques|(1<<i),ans|(1<<i),v1),dp(ques|(1<<i),ans,v2))+1);
    }
    return d[ques][ans];
}

int main()
{
    while(~scanf("%d%d",&m,&n)&&(n+m))
    {
        for(int i = 0;i<n;i++)
            scanf("%s",stat[i]);
        vector <int> v;
        for(int i =0;i<n;i++)
            v.push_back(i);
        memset(d,-1,sizeof(d));
        printf("%d\n",dp(0,0,v));
    }
    return 0;
}

/*
3 4
001
011
100
000
*/


你可能感兴趣的:(UVALive 4643 Twenty Questions)