现在的位置: 首页 > 综合 > 正文

UVa #1252 Twenty Questions (例题9-16)

2018年10月14日 ⁄ 综合 ⁄ 共 1091字 ⁄ 字号 评论关闭

2.5s低空飘过

集合上的动态规划,中间状态一般就是全集的子集合。为了精确的描述状态,一般增加一个或多个维度。

这道题全集就是所有的特征,中间状态就是询问了某一些特征。询问的结果则要用另一个维度来储存。

动态规划的过程就是把所有可能的询问遍历一遍,在每次遍历的同时,遍历所有的询问结果的可能性。边界值及时返回、重叠子问题及时返回,避免重复运算。

Run Time: 2.542s

#define UVa  "LT9-16.1252.cpp"		//Twenty Questions
char fileIn[30] = UVa, fileOut[30] = UVa;

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<ctype.h>

using namespace std;

//Global Variables. Reset upon Each Case!
const int maxm = 11 + 1, maxn = 128 + 5;
const int INF = maxm + 5;
int m, n;
int ft[maxn];
int cnt[1<<maxm][1<<maxm];
int d[1<<maxm][1<<maxm];
/////

int dp(int s, int a) {
    if(d[s][a] != -1) return d[s][a];
    int& ans = d[s][a];
    if(cnt[s][a] == 1) return ans = 0;
    ans = INF;
    for(int i = 0; i < m; i ++) {
        int f = 1<<i;
        if(!(s&f)) {
            int d1 = dp(s|f, a);
            int d2 = dp(s|f, a|f);
            ans = min(ans, max(d1, d2) + 1);
        }
    }
    return ans;
}

int main() {
    while(scanf("%d%d", &m, &n) && m) {
        char ch;
        memset(ft, 0, sizeof(ft));
        memset(cnt, 0, sizeof(cnt));
        memset(d, -1, sizeof(d));
        for(int i = 0; i < n; i ++) {
            for(int j = 0; j < m; j ++) {
                do{ch = getchar();}while(!isalnum(ch));
                ft[i] = ft[i] * 2 + ch - '0';
            }
        }
        for(int s = 0; s <= (1<<m)-1; s ++) {   //O(n*2^m)
            for(int i = 0; i < n; i ++) {
                int tmp = s & ft[i];
                cnt[s][tmp] ++;
            }
        }
        printf("%d\n", dp(0,0));                //O(m*3^m)
                                                //Total: O(n*2^m + m*3^m)
    }
    return 0;
}

抱歉!评论已关闭.