zoukankan      html  css  js  c++  java
  • Loppinha, the boy who likes sopinha Gym

    https://vjudge.net/contest/299302#problem/E

    题意:给出一个01 0101串,然后能量计算是连续的1就按1, 2, 3的能量加起来。然后给出起始的能量,求最少减掉几个一是起始的能量不被消耗完。

    思路:不能用贪心,比如11111,按理说拿一个最好是中间分开,但是那两次的这种情况下应该是要把第二个和第四个拿掉来最小

    所以要用记忆化搜索或dp;

    记忆化搜索 

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 505;
    const int inf = 1e9 + 7;
    int dp[maxn][maxn];////dp[i][j]表示处理了前i个数字,然后还可以换j次,i个数字后还所需要消耗的能量
    char ch[maxn];
    int n, m;
    
    int cal(int x) {
        return x * (x + 1) / 2;
    }
    //递归边界是刚好处理完n个数字,并且要求k>=0
    int dfs(int p, int k) {//前p个数字,换k次
        if(k < 0) return inf;
        if(p >= n) return 0;//注意这两句不能换位置!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        if(dp[p][k] != -1) return dp[p][k];
        if(ch[p] == '0') return dfs(p + 1, k);//为0就肯定不用换,继续递归
        dp[p][k] = inf;//先初始化为INF
        int i;
        for(i = p; i < n && ch[i] == '1'; i++) {//当有一个位置为0的时候跳出循环
            dp[p][k] = min(dp[p][k], dfs(i + 1, k - 1) + cal(i - p));//考虑将第i个1换成0
        }
        dp[p][k] = min(dp[p][k], dfs(i + 1, k) + cal(i - p));//第i位置是0
        return dp[p][k];
    }
    
    int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", ch);
    memset(dp, -1, sizeof(dp));
    for(int i = 0; i <= n; i++) {
        if(dfs(0, i) <= m) {
            printf("%d
    ", i);
            return 0;
        }
    }
    return 0;
    }

    dp做法:三维dp。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 505;
    const int INF = 0x3f3f3f3f;
    int n, k;
    int dp[2][N][N];
    char str[N];
    
    
    int main() {
        scanf("%d%d", &n, &k);
        scanf("%s", str + 1);
        memset(dp, INF, sizeof(dp));
        int cur = 0, last = 1;
        dp[last][0][0] = 0;//表示第i位,前面i改了j个1,然后累积了k个连续的1。
        for(int i = 1; i <= n; i++) {
            memset(dp[cur], INF, sizeof(dp[cur]));//先全部初始化一个最大值。
            if(str[i] != '0') {
                for(int j = 0; j <= n; j++) {
                    for(int k = 0; k <= n; k++) {
                        if(dp[last][j][k] != INF) {
                            dp[cur][j][k + 1] = min(dp[cur][j][k + 1], dp[last][j][k] + k + 1);//表示这一位的1不该得到的最小值。
                            dp[cur][j + 1][0] = min(dp[cur][j + 1][0], dp[last][j][k]);//表示这一位的1改为0得到的最小值。
                        }
                    }
                }
            }
            else {
                for(int j = 0; j <= n; j++) {
                    for(int k = 0; k <= n; k++) {
                        if(dp[last][j][k] != INF) {
                            dp[cur][j][0] = min(dp[cur][j][0], dp[last][j][k]);//表示这一位为0的最下值。
                        }
                    }
                }
            }
            swap(cur, last);
        }
        int ans = n;
        for(int i = 0; i <= n; i++) {
            for(int j = 0; j <= n; j++) {
                if(dp[last][i][j] <= k) {
                    ans = i;
                    break;  
                }
            }
            if(ans != n) break;
        }
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    Yii2中多表关联查询(join、joinwith)
    Yii2.0实用功能技巧解密之——分页功能
    Yii2.0中文开发向导——RBAC(基于角色的访问控制权限)表结构原理分析
    Yii2.0源码分析之——控制器文件分析(Controller.php)创建动作、执行动作
    Yii2.0源码分析之——主题(Theme)
    Yii2.0源码分析之——YiiBase自动加载类、引用文件(autoload)
    MySQL 性能调优的10个方法
    PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询–算法
    ThinkPHP3.2.3验证码显示、刷新、校验
    Yii2 基于RESTful架构的 advanced版API接口开发 配置、实现、测试
  • 原文地址:https://www.cnblogs.com/downrainsun/p/10806997.html
Copyright © 2011-2022 走看看