• [HDOJ5573]Binary Tree(找规律,贪心)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5573

    这个题……规律暂时还找不到,先贡献两发TLE的代码吧,一个dfs一个状压枚举。

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <iomanip>
     4 #include <cstring>
     5 #include <climits>
     6 #include <complex>
     7 #include <fstream>
     8 #include <cassert>
     9 #include <cstdio>
    10 #include <bitset>
    11 #include <vector>
    12 #include <deque>
    13 #include <queue>
    14 #include <stack>
    15 #include <ctime>
    16 #include <set>
    17 #include <map>
    18 #include <cmath>
    19 
    20 using namespace std;
    21 
    22 typedef long long ll;
    23 const int maxn = 66;
    24 
    25 ll n, k;
    26 ll path[maxn][3];
    27 int pcnt;
    28 //1 + 0 -
    29 bool exflag;
    30 void dfs(ll cur, ll lv, ll id) {
    31     if(exflag) return;
    32     if(cur == n && lv == k) {
    33         for(ll i = 0; i < pcnt; i++) {
    34             printf("%I64d %c
    ", path[i][0], path[i][1] == 1 ? '+' : '-');
    35         }
    36         exflag = 1;
    37         return;
    38     }
    39     if(cur != n && lv == k) return;
    40 
    41     path[pcnt][0] = id;
    42     path[pcnt++][1] = 1;
    43     dfs(cur+id ,lv+1, id*2);
    44     pcnt--;
    45 
    46     path[pcnt][0] = id;
    47     path[pcnt++][1] = 1;
    48     dfs(cur+id ,lv+1, id*2+1);
    49     pcnt--;
    50 
    51     path[pcnt][0] = id;
    52     path[pcnt++][1] = 0;
    53     dfs(cur-id ,lv+1, id*2);
    54     pcnt--;
    55 
    56     path[pcnt][0] = id;
    57     path[pcnt++][1] = 0;
    58     dfs(cur-id ,lv+1, id*2+1);
    59     pcnt--;
    60 }
    61 
    62 int main() {
    63     // freopen("in", "r", stdin);
    64     int T, _ = 1;
    65     scanf("%d", &T);
    66     while(T--) {
    67         scanf("%I64d %I64d", &n, &k);
    68         pcnt = 0; exflag = 0;
    69         printf("Case #%d:
    ", _++);
    70         dfs(0, 0, 1);
    71     }
    72     return 0;
    73 }
    DFS
    #include <algorithm>
    #include <iostream>
    #include <iomanip>
    #include <cstring>
    #include <climits>
    #include <complex>
    #include <fstream>
    #include <cassert>
    #include <cstdio>
    #include <bitset>
    #include <vector>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <ctime>
    #include <set>
    #include <map>
    #include <cmath>
    
    using namespace std;
    
    typedef long long ll;
    const int maxn = 66;
    ll n, k;
    ll f[maxn];
    ll ans[maxn];
    bool sub[maxn];
    
    void init() {
        f[0] = 1;
        for(int i = 1; i < maxn; i++) {
            f[i] = f[i-1] * 2;
        }
    }
    
    int main() {
        // freopen("in", "r", stdin);
        int T, _ = 1;
        init();
        scanf("%d", &T);
        while(T--) {
            scanf("%I64d %I64d", &n, &k);
            for(int i = 1; i <= k; i++)
                ans[i] = f[i-1];
            if(n % 2 == 0) ans[k]++;
            ll nn = 1 << k;
            bool exflag = 0;
            for(ll i = 1; i < nn; i++) {
                if(exflag) break;
                ll cur = 0;
                memset(sub, 0, sizeof(sub));
                for(ll j = 1; j <= k; j++) {
                    if((1 << j) & i) {
                        sub[j] = 1;
                        cur -= ans[j];
                    }
                    else cur += ans[j];
                }
                if(cur == n) exflag = 1;
            }
            printf("Case #%d:
    ", _++);
            for(ll i = 1; i <= k; i++) {
                printf("%I64d ", ans[i]);
                if(sub[i]) printf("-
    ");
                else printf("+
    ");
            }
        }
        return 0;
    }
    ENUM

    这个题想了很多天,想明白了其实还蛮简单的。

    题目给了一棵满二叉树,按照层次遍历从左到右挨个编号1 2 3....问蛤蛤从根节点向下走,走到一个点可以加上当前节点编号也可以删掉当前节点编号。问走k层能否恰好续够n。

    题目中给了一个条件:N2^K2^60

    因为读题坑掉了没看到这个条件,浪费了很多时间在例如n=10 k=3的情况上。这种情况在我的搜索中是完全有结果的,但是实际上这个情况不会在题目中出现,因为8<10。

    这样就好办了,我们考虑任何一个十进制数都可以表示为二进制,这个二进制表示了某一位上是否要加上对应的2的幂次。

    (以上皆为口胡+脑补,正常题解在下面)

    N<=2^k意味着我们总能找到第k+1个节点,使得N小于k+1节点的数值。既然如此,我们贪心地选取最左边的一条链。这样,最左边那个点必然是整层最小的。对于本题目而言,总有2^(k+1)-1≥n。

    由于最左侧的链均为2的幂次,我们以前的知识中一定有这样一条规律:2^(k)-1=∑i(1,k-1)2^i。表达不清楚,举个例子:32-1=1+2+4+8+16。

    我们假设整条长度为k链都是加的,那它的总和就是2^(k+1)-1,我们现在知道要求的n,那我们不需要的那部分的值为2^(k+1)-1-n。

    假设这个值为x,那x也总是能表达为一个二进制数,我们只需要在这个链子上找到可以表示x的二进制数的位置,把它们标记为'-'即可。

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <iomanip>
     4 #include <cstring>
     5 #include <climits>
     6 #include <complex>
     7 #include <fstream>
     8 #include <cassert>
     9 #include <cstdio>
    10 #include <bitset>
    11 #include <vector>
    12 #include <deque>
    13 #include <queue>
    14 #include <stack>
    15 #include <ctime>
    16 #include <set>
    17 #include <map>
    18 #include <cmath>
    19 
    20 using namespace std;
    21 
    22 typedef long long ll;
    23 const int maxn = 66;
    24 ll n, k;
    25 ll f[maxn];
    26 ll ans[maxn];
    27 bool sub[maxn];
    28 
    29 void init() {
    30     f[0] = 1;
    31     for(int i = 1; i < maxn; i++) {
    32         f[i] = f[i-1] * 2;
    33     }
    34 }
    35 
    36 int main() {
    37     // freopen("in", "r", stdin);
    38     int T, _ = 1;
    39     init();
    40     scanf("%d", &T);
    41     while(T--) {
    42         scanf("%I64d %I64d", &n, &k);
    43         memset(sub, 0, sizeof(sub));
    44         for(int i = 1; i <= k; i++)
    45             ans[i] = f[i-1];
    46         ll remain = f[k] - n - 1;
    47         if(n % 2 == 0) {
    48             ans[k]++;
    49             remain++;
    50         }
    51         remain >>= 1;
    52         int cnt = 1;
    53         while(remain) {
    54             if(remain % 2 == 1) sub[cnt] = 1;
    55             remain >>= 1;
    56             cnt++;
    57         }
    58         printf("Case #%d:
    ", _++);
    59         for(int i = 1; i <= k; i++) {
    60             printf("%I64d ", ans[i]);
    61             sub[i] ? printf("-
    ") : printf("+
    ");
    62         }
    63     }
    64     return 0;
    65 }
  • 相关阅读:
    VestaCP中国用户遭到大量DDOS攻击
    ZooKeeper设置ACL权限控制
    linux rsync 指定用户名和密码的方式同步
    关于Apache HTTPD 2.2.15的部分漏洞修复建议
    AutoMapper官方文档(二)【升级指南】
    openssl升级
    MongoDB如何无缝版本升级
    mysql在线升级更新步骤
    手动升级kubernetes集群
    更新Docker容器
  • 原文地址:https://www.cnblogs.com/kirai/p/5430063.html
Copyright © 2020-2023  润新知