【UVA1252】Twenty Questions

题面

有n(n≤128)个物体,m(m≤11)个特征。每个物体用一个m位01串表示,表示每个特征是具备还是不具备。
我在心里想一个物体(一定是这n个物体之一),由你来猜。
你每次可以询问一个特征,然后我会告诉你:我心里的物体是否具备这个特征。
当你确定答案之后,就把答案告诉我(告知答案不算“询问”)。
如果你采用最优策略,最少需要询问几次能保证猜到?
例如,有两个物体:1100和0110,只要询问特征1或者特征3,就能保证猜到。

分析

dp[k][c]存状态,其中k表示已经询问了的特征,c表示心里所想物体已经确定具备的特征,存的是还需要询问的次数。
每一次选择一个还没有被确定的特征i,去更新的dp[k|i][c|i]=max(dp[k|i][c|i],dp[k|i][c])+1
状态太多,用记忆化搜索。边界是这些特征能确定的物品数量,如果<=1,就应该返回了

代码

#include<bits/stdc++.h>
using namespace std;
#define N 12
#define INF 0x3f3f3f3f
int n,m,w[N*N],dp[1<<N][1<<N];
char s[N*N];
inline void init()
{
    memset(w,0,sizeof(w));
    memset(dp,0x3f,sizeof(dp));
}

inline int dfs(int k,int c)
{
    int &ans=dp[k][c];
    if(ans!=INF)return ans;
    int cnt=0;
    for(int i=1;i<=n;i++)
        if((k&w[i])==c)cnt++;
    if(cnt<=1) {dp[k][c]=0;return 0;}
    for(int i=1;i<=m;i++)
        if((k&(1<<i-1))==0)
            ans=min(ans,max(dfs(k|(1<<i-1),c|(1<<i-1)),dfs(k|(1<<i-1),c))+1);
    return ans;
}

int main()
{
    while(scanf("%d%d",&m,&n)&&m)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            for(int j=1;j<=m;j++)
                if(s[j-1]=='1')w[i]|=(1<<j-1);
        }
        printf("%d\n",dfs(0,0));
    }
    return 0;
}

 

posted @ 2018-10-15 19:06  WJEMail  阅读(180)  评论(0编辑  收藏  举报