zoukankan      html  css  js  c++  java
  • HihoCoder 1527 动态规划,贪心

    https://hihocoder.com/problemset/problem/1527

    时间限制:20000ms

    单点时限:1000ms

    内存限制:256MB

    描述

    在写代码时,我们经常要用到类似 x × a 这样的语句( a 是常数)。众所周知,计算机进行乘法运算是非常慢的,所以我们需要用一些加法、减法和左移的组合来实现乘一个常数这个操作。具体来讲, 我们要把 x × a 替换成:(x<<a0) op1 (x<<a1) op2 (x<<a2) ... opn (x<<an) 这样的形式,其中opi 是+或者-。

    举个例子:x × 15 = (x<<4) - (x<<0)。

    在本题中,假设左移(包括左移0)和加法、减法所需要的时间都是一个单位的时间,上述的例子所需要的时间是3。

    现在给定常数 a 的二进制形式,求实现 x × a 最少需要多少单位的时间。

    输入

    一个01串,表示 a 的二进制形式,从左到右分别是从高位到低位。

    0 < 01串的长度之和 ≤ 106

    a > 0。

    输出

    输出一个数,表示最小需要多少单位的时间可以实现 x × a

    样例输入 1111样例输出 3

    错解贪心选择超过两个连续的1的决策不如使用高位减低位的方法,110不如1<<3 – 1<<1然后,单个1选择直接加上。如果两个大块(2个连续1以上)中间之隔为1个0,那么可以合并,110110不如 1<<6 – 1<<4 + 1<<3 – 1<<1 = 1<<6 – 1 <<3 – 1<<1

    是我太弱,所以没有贪出来,少考虑了一种情况就是对于类似1101011这样,可以抉择把0填满然后变成全1,用1<<7-1<<0.

    错误代码:

    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    #include <stdlib.h>
    #include <vector>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <string>
    #include <math.h>
    using namespace std;
    typedef pair<int,int> P;
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-9;
    const int N = 1e6 + 5;
    
    char s[N];
    
    int main()
    
    {
        while(scanf("%s", s) != EOF)
        {
            int n = strlen(s);
            int cnt = 0;
            int i = 0;
            while(i < n)
            {
                int k = 0;
                while(i < n && s[i] == '1')
                {
                    k++;
                    i++;
                }
                if(k == 1) cnt++;
                else if(k >= 2) cnt += 2;
                if(k >= 2 && i+2 < n && s[i+1] == '1' && s[i+2] == '1')
                    cnt -= 1;
                if(i < n && s[i] == '0')
                    i++;
            }
            printf("%d
    ", 2*cnt-1);
        }
        return 0;
    }

    AC贪心:

    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    #include <stdlib.h>
    #include <vector>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <string>
    #include <math.h>
    using namespace std;
    typedef pair<int,int> P;
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-9;
    const int N = 1e6 + 5;
    
    char s[N];
    int main()
    {
        while(scanf("%s", s) != EOF)
        {
            int n = strlen(s);
            int cnt = 0;
            int i = 0,k,flag=0;
            while(i < n)
            {
                if(!flag)
                    k = 0;
                flag = 0;
                while(i < n && s[i] == '1')
                {
                    k++;
                    i++;
                }
                if(k == 1) cnt++;
                else if(k >= 2) cnt += 2;
                if(k >= 2 && i+1 < n && s[i+1] == '1')
                {
                    cnt -= 1;
                    flag = 1;
                    s[i] = '1';
                    k++;
                }
                if(i < n && s[i] == '0')
                    i++;
            }
            printf("%d
    ", 2*cnt-1);
        }
        return 0;
    }
    题解:很多都是二幂划分的解释,也可以用dp来做
    从低位往高位考虑。dp[i]表示第i位的时候需要进行最少操作数
    如果当前位是0,dp[i] = dp[i-1]
    如果当前位是1,可以有两种选择,直接加上dp[i] = dp[i-1] + 1;
    或者,把某一部分的0全部补上,然后用高位1减去,例如01100 = 10000 – 00100,也就是 [x, i]全部都变成1,也就是要补上x~i的0
    dp[i] =min{ dp[x-1] + 2 + sum[i] – sum[x-1]}
    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    #include <stdlib.h>
    #include <vector>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <string>
    #include <math.h>
    using namespace std;
    typedef pair<int,int> P;
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-9;
    const int N = 1e6 + 5;
    
    char s[N];
    int sum[N], dp[N];
    int main()
    {
        scanf("%s", s+1);
        int n = strlen(s+1);
        memset(dp,0,sizeof(dp));
        memset(sum, 0, sizeof(sum));
        reverse(s+1,s+1+n);
        for(int i = 1; i <= n; i++) sum[i] =sum[i-1] + (s[i] == '0');
        dp[0] = 0;
        int mx = -1;
        for(int i = 1; i <= n; i++)
        {
            if(s[i] == '0')
                dp[i] = dp[i-1];
            else
            {
                dp[i] = dp[i-1] + 1;
                if(mx > 0)
                    dp[i] = min(dp[i], dp[mx-1] + 2 + sum[i] - sum[mx-1]);
            }
            if(mx == -1 || dp[i-1] + 2 + sum[i+1] - sum[i-1] <= dp[mx-1] + 2 + sum[i+1] - sum[mx-1])
                mx = i;
        }
        printf("%d
    ", 2*dp[n]-1);
        return 0;
    
    }
    如果有错误,请指出,谢谢
  • 相关阅读:
    Atitit sql计划任务与查询优化器统计信息模块
    Atitit  数据库的事件机制触发器与定时任务attilax总结
    Atitit 图像处理知识点体系知识图谱 路线图attilax总结 v4 qcb.xlsx
    Atitit 图像处理 深刻理解梯度原理计算.v1 qc8
    Atiti 数据库系统原理 与数据库方面的书籍 attilax总结 v3 .docx
    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
    Atitit View事件分发机制
    Atitit 基于sql编程语言的oo面向对象大规模应用解决方案attilax总结
    Atitti 存储引擎支持的国内点与特性attilax总结
    Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折
  • 原文地址:https://www.cnblogs.com/Alruddy/p/7336983.html
Copyright © 2011-2022 走看看