zoukankan      html  css  js  c++  java
  • UVa 1252

    链接:

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3693

    题意:

    有n(n≤128)个物体,m(m≤11)个特征。每个物体用一个m位01串表示,表示每个特征是具备还是不具备。
    我在心里想一个物体(一定是这n个物体之一),由你来猜。
    你每次可以询问一个特征,然后我会告诉你:我心里的物体是否具备这个特征。
    当你确定答案之后,就把答案告诉我(告知答案不算“询问”)。
    如果你采用最优策略,最少需要询问几次能保证猜到?
    例如,有两个物体:1100和0110,只要询问特征1或者特征3,就能保证猜到。

    分析:

    为了叙述方便,设“心里想的物体”为W。首先在读入时把每个物体转化为一个二进制整数。
    不难发现,同一个特征不需要问两遍,所以可以用一个集合k表示已经询问的特征集。
    在这个集合k中,有些特征是W所具备的,剩下的特征是W不具备的。
    用集合c来表示“已确认物体W具备的特征集”,则c一定是k的子集。
    设d(k,c)表示已经问了特征集k,其中已确认W所具备的特征集为c时,还需要询问的最小次数。
    如果下一次提问的对象是特征i(这就是“决策”),则询问次数为:max{d(k+{i},c+{i}),d(k+{i},c)}+1。
    考虑所有的i,取最小值即可。边界条件为:如果只有一个物体满足“具备集合c中的所有特征,
    但不具备集合k-c中的所有特征”这一条件,则d(k,c)=0,因为无须进一步询问,已经可以得到答案。
    因为c为k的子集,所以状态总数为3^m,时间复杂度为O(m*3^m)。
    对于每个k和c,可以先把满足该条件的物体个数统计出来,保存在amt[k][c],避免状态转移的时候重复计算。
    统计amt[k][c]的方法是枚举k和物体,时间复杂度为O(n*2^m),对于本题来说可以忽略不计。

    代码:

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 const int INF = 0x3f3f3f3f;
     6 const int UPM = 11;
     7 const int UPN = 128;
     8 int n, m, d[1<<UPM][1<<UPM], amt[1<<UPM][1<<UPM];
     9 char s[UPN+5][UPM+5];
    10 
    11 void init() {
    12     int u = 1<<m;
    13     for(int k = 0; k < u; k++) {
    14         amt[k][0] = 0;
    15         d[k][0] = INF;
    16         for(int c = k; c; c = k&(c-1)) amt[k][c] = 0, d[k][c] = INF;
    17     }
    18     for(int t = 0; t < n; t++) {
    19         int c = 0;
    20         for(int i = 0; i < m; i++) if(s[t][i] == '1') c |= (1<<i);
    21         for(int k = 0; k < u; k++) amt[k][k&c]++;
    22     }
    23 }
    24 
    25 int dp(int k, int c) {
    26     int& res = d[k][c];
    27     if(res != INF) return res;
    28     if(amt[k][c] < 2) return res = 0;
    29     for(int i = 0; i < m; i++) {
    30         if(k&(1<<i)) continue;
    31         int k2 = k|(1<<i), c2 = c|(1<<i);
    32         int need = max(dp(k2,c), dp(k2,c2));
    33         res = min(res, need);
    34     }
    35     return res += 1;
    36 }
    37 
    38 int main() {
    39     while(scanf("%d%d", &m, &n) && m) {
    40         for(int i = 0; i < n; i++) scanf("%s", s[i]);
    41         init();
    42         printf("%d
    ", dp(0,0));
    43     }
    44     return 0;
    45 }
  • 相关阅读:
    treeview十八般武艺,js选择和绑定权限树
    开源WebOS
    公交车路线查询系统后台数据库设计
    网页信息抓取
    一步一步打造WebIM(3)——性能测试
    WebBrowser介绍——Javascript与C++互操作
    .NET文档生成工具ADB[更新至2.3]
    一步一步打造WebIM(4)——Comet的特殊之处
    在SQL Server中对视图进行增删改
    开源企业即时通讯和在线客服
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9746198.html
Copyright © 2011-2022 走看看