Uva1252

来源:互联网 发布:ps4淘宝被禁的游戏 编辑:程序博客网 时间:2024/06/05 20:46

题目链接

给出一个例子来理解题意:m=5,n=4时有

10100

11000

00001

00010

从左到右表示1-m个特征,现在询问第一个位置就可以把原来四组分为{(1),(2)}和{(3),(4)} 然后再区分(1)和(2)可以询问位置2或3 区分(3)和(4)可以询问位置4或5。

假设所要猜的物体为w,我们用一个集合s表示所询问的特征,用集合a表示在集合s里面w所具有的特征,即a是s的子集。

d(s,a)表示询问过特征集s,确认w所具有的特征集为a,还需要询问的最小次数,下一次询问的特征为k。次数:max{d(s+{k},a+{k}),d(s+{k},a)}+1

#include<cstdio>#include<ctime>#include<cstring>#include<algorithm>#include<cassert>#include<iostream>using namespace std;const int maxn = 1 << 12;const  int INF = 0x3f3f3f3f;char str[20];int m, n;int d[maxn][maxn], p[maxn], cnt[maxn][maxn];int dp(int s, int a){    if (d[s][a] != INF)        return d[s][a];    int num = 0;    for (int i = 0; i < n; i++)        if ((p[i] & s)==a)            num++;    if (num <= 1)//如果只有一个或没有物体符合则需要需要询问的次数为0    {        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!=0)    {        memset(p, 0, sizeof(p));        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')                    p[i] |= (1 << j);//用位运算来表示物体的特征            }        }        printf("%d\n", dp(0, 0));//一开始没有询问所以s和a为空集    }    return 0;}