其他分享
首页 > 其他分享> > UVA-1252 Twenty Questions (状压dp)

UVA-1252 Twenty Questions (状压dp)

作者:互联网

题意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同)最小需要多少次询问?

分析:要做的是鉴别出来我心里所想的那一个物品(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需要遍历,这里,已经考虑了最坏的情况,那么就可以只考虑次数了,取最小的次数。 用记忆化搜索的形式实现即可。考虑所有的i,取最小值即可。边界条件为:如果只有一个物体满足“具备集合c中的所有特征,但不具备集合k-c中的所有特征”这一条件,则d(k,c)=0,因为无须进一步询问,已经可以得到答案。取最大最小这里理解了老半天。还需要回过头再理解。

参考:https://www.cnblogs.com/mu-ye/p/5695675.html

代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1 << 12;
const int INF = 0x3f3f3f3f;

string str;
int w[130];
int d[maxn][maxn];
int m, n;

int dp(int s, int a)
{
    int& ans = d[s][a];
    if (ans != INF)  return ans;
    int cnt = 0;
    for (int i = 0; i<n; i++)
        //边界条件判断,如果cnt<=1,则说明能判断出来了
    if ((w[i] & s) == a)  cnt++;
    if (cnt <= 1){ d[s][a] = 0; return 0; }

    for (int i = 0; i<m; i++)
    {
        if (s&(1 << i))continue;
        ans = min(ans, max(dp(s | 1 << i, a | 1 << i), dp(s | 1 << i, a)) + 1);
    }
    return ans;
}

int main()
{
    while (cin>>m>>n &&n&&m)
    {
        memset(w, 0, sizeof(w));
        memset(d, INF, sizeof(d));
        for (int i = 0; i<n; i++)
        {
            cin >> str;
            for (int j = 0; str[j]; j++)
            if (str[j] == '1')  w[i] |= (1 << j);
        }
        printf("%d\n", dp(0,0));
    }
}

 

标签:特征,Twenty,询问,状压,次数,1252,str,物品,考虑
来源: https://blog.csdn.net/tianwei0822/article/details/94589712