UVA

状压dp,用s表示已经询问过的特征,a表示W具有的特征。

当满足条件的物体只有一个的时候就不用再猜测了。对于满足条件的物体个数可以预处理出来

转移的时候应该枚举询问的k,因为实际上要猜的物品是不确定的,要么k是W所具有的,要么k不是W所具有的,

要保证能猜到那么就应该取最坏情况下的最小值,所以有转移方程:dp[s][a] = min(max(dp[s|1<<k][a],dp[s|1<<k][a|1<<k]))。

询问特征可能转移到一个非法的状态,即满足条件的物品数量为0个。根据转移方程应该返回0。

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

const int maxm = 11, maxn = 130;

int cnt[1<<maxm][1<<maxm], m, n, dp[1<<maxm][1<<maxm];

bitset<maxm> obj[maxn];
const int INF = 0x3fffffff;

void preDeal()
{
    for(int s = 0,M = 1<<m; s < M; s++){
        fill(cnt[s],cnt[s]+s+1,0);
        fill(dp[s],dp[s]+s+1,INF);
        for(int i = 0; i < n; i++){
            cnt[s][obj[i].to_ulong()&s]++;
        }
    }
}

int dfs(int s,int a)
{
    if(cnt[s][a] <= 1) return  0;
    int &ans = dp[s][a];
    if(ans<INF) return ans;
    for(int k = 0; k < m; k++){
        if(s&1<<k) continue;
        int ns = s|1<<k;
        ans = min(ans,max(dfs(ns,a),dfs(ns,a|1<<k))+1);
    }
    return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d
",&m,&n),m){
        for(int i = 0; i < n; i++){
            cin>>obj[i];
        }
        preDeal();
        printf("%d
",dfs(0,0));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4748841.html