• poj 3605 Sheryl's Circuit I 代码


    http://poj.org/problem?id=3605

       

      这个暑假的个人赛打的一塌糊涂...成绩有多难看还真不想说...

      这么多场个人赛,暴露出我的知识面是多么狭窄..可能也是跟我考试前荒废了那么一段时间是有关的..

      

      记录比赛中一道无聊的,超简单的,可是我那时做不出的一道树dp中最水的题。题意很简单的,不解释太多,就简单说一下我的做法。一棵与或表达式树,操作符都已经排好序了,于是我从最底层开始,逐层往上dp。dp数组是储存该节点从0变成1最少要改变多少个控制信号,

      在每一层里,如果是与:dp[i] = dp[i << 1] + dp[i << 1 | 1];

    如果是或:dp[i] = min2(dp[i << 1] + dp[i << 1 | 1], min2(dp[i << 1 | 1], dp[i << 1]));

      有一个很关键的地方是,除了第一次从0变1要改变dp[0]次,其他任何一次无论是从0变成1还是从1变成0,都只需改变一个控制信号。其实原因很简单,既然能找到一个从初始状态(全部是0)改变dp[0]次就可以把输出信号变成1的方法,那么如果只改变dp[0]-1次,这时的输出必然是0。也就是说,除了第一次从0变成1是要找最小操作,其余都只需1步的操作就可以完成了。

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 
     5 #define debug 0
     6 
     7 int min2(int _a, int _b){return _a < _b ? _a : _b;}
     8 int max2(int _a, int _b){return _a > _b ? _a : _b;}
     9 
    10 int dp[8200];
    11 int op[8200];
    12 char s[10005];
    13 
    14 void init(int k){
    15     int end = 1 << k;
    16 
    17     for (int i = 0; i < end; i++){
    18         dp[i] = 1;
    19     }
    20 }
    21 
    22 int deal(int k){
    23     if (!k) return dp[0];
    24     int len = 1 << (k - 1);
    25 
    26     for (int i = 0; i < len; i++){
    27         int p = i + len;
    28 
    29         if (op[p]){
    30             dp[i] = dp[i << 1] + dp[i << 1 | 1];
    31         }
    32         else{
    33             dp[i] = min2(dp[i << 1] + dp[i << 1 | 1], min2(dp[i << 1 | 1], dp[i << 1]));
    34         }
    35     }
    36     #if debug
    37     for (int i = 0; i < len << 1; i++){
    38         printf("%d\n", dp[i]);
    39     }
    40     puts("");
    41     #endif
    42 
    43     return deal(k - 1);
    44 }
    45 
    46 int cnt(int n){
    47     int k = -1;
    48 
    49     while (n){
    50         k++;
    51         n /= 2;
    52     }
    53 
    54     return k;
    55 }
    56 
    57 int main(){
    58     int c;
    59 
    60     scanf("%d", &c);
    61 
    62     while (c--){
    63         int n;
    64 
    65         scanf("%d", &n);
    66         scanf("%s", s);
    67         for (int i = 1; i < n; i++){
    68             scanf("%d", &op[i]);
    69         }
    70 
    71         init(cnt(n));
    72         int tmp = deal(cnt(n));
    73         #if debug
    74         printf("cnt %d  tmp %d\n", cnt(n), tmp);
    75         #endif
    76 
    77         int len = strlen(s);
    78         int p = 0, cnt = 0;
    79 
    80         while (p < len && s[p] == '0') p++;
    81         if (p != len){
    82             cnt += tmp;
    83         }
    84         for (int i = p + 1; i < len; i++){
    85             if (s[i] != s[i - 1]) cnt++;
    86         }
    87         printf("%d\n", cnt);
    88     }
    89 
    90     return 0;
    91 }
  • 相关阅读:
    pixijs设置层级的方法
    6.Linux CPU实时监控mpstat命令详解
    5.Linux vmstat命令详解
    4.Linux iostat命令详解
    3.linux top 命令详解
    2.linux sort 命令详解
    1.Linux vim命令详解
    0.Linux命令参考博客
    洛谷 U140956 新漂亮国大选
    CF457C Elections
  • 原文地址:https://www.cnblogs.com/LyonLys/p/poj_3605_Lyon.html
Copyright © 2020-2023  润新知