【状压dp】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem E. Guessing Game

题意:给你n个两两不同的零一串,Alice在其中选定一个,Bob去猜,每次询问某一位是0 or 1。问你最坏情况下最少要猜几次。

f(22...2)表示当前状态的最小步数,2表示这位没确定,1表示确定为1,0表示确定为0。

首先枚举去问哪一位,从这些方案中取最小者。

这里的MAX(a,b)进行重定义,如果a,b中存在-1,则为真的max(a,b),否则为max(a,b)+1。

f(222)=min(MAX(f(022),f(122)),MAX(f(202),f(212)),MAX(f(220),f(221)));

边界是那些读入的串为0,读入的里面没有的串的值为-1。

队友的代码:

#include <cmath>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int T,top,l,n,f[5000000];
char ch;
int dfs(int x,int deep)
{
    if(f[x]!=-2) return f[x];
    if(deep==l) return f[x]=-1;
    int xx=x,temp=1;
    int nowans=100;
    for(int i=1;i<=l;++i)
    {
        if(xx%3==2)
        {
            int xxx=x-temp*2;
            int ans0=dfs(xxx,deep+1);
            int ans1=dfs(xxx+temp,deep+1);
            int tempans=max(ans0,ans1);
            if(ans0!=-1&&ans1!=-1) tempans++;
            nowans=min(nowans,tempans);
        }
        xx/=3;
        temp*=3;
    }
    return f[x]=nowans;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&l);
        top=1;
        for(int i=1;i<=l;++i)
            top=top*3;
        top-=1;
        for(int i=0;i<=top;++i)
            f[i]=-2;
        for(int i=1;i<=n;++i)
        {
            int now=0;
            for(int i=1;i<=l;++i)
            {
                while(ch=getchar(),ch!='0'&&ch!='1');
                now=now*3+ch-'0';
            }
            f[now]=0;
        }
        printf("%d
",dfs(top,0));
        for(int i=0;i<=top;++i)
            f[i]=-2;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/8849356.html