• CodeForces 544C (Writing Code)(dp,完全背包)


    题意:有n个程序员,要协作写完m行代码,最多出现b个bug,第i个程序员每写一行代码就会产生a[i]个bug,现在问,这n个人合作来写完这m行代码,有几种方案使得出的bug总数不超过b(题中要求总方案数要对一个特定的数取模)?

    分析:

    这道题目属于dp中的计数类型,即求出方案数。一般来说,为了求出方案数,要将现存的问题分为2个或2个以上完全不重叠的子问题。这就类似于,有n层楼梯,你可以一次跨1阶,或者一次跨2阶,问你有多少种上楼梯的方法一样。

    在上楼梯问题中,我们可以在当前状态的第一步跨上1阶,或者在当前状态的第一步跨上2阶,这样,原问题就被分解成了两个完全没有交集的子问题,因为第一步跨法不同,那么不论我们以后怎么上楼梯,都不可能出现相同的走法。即dp[i] = dp[i-1] + dp[i-2]。

    那么,对于这道题,我们可以将是否让第i个程序员写代码作为分界标准来分出子问题。

    状态定义:dp[i][j][k]--->现在有i个程序员合作,一共有j行代码待完成,最多出k个bug的方案总数。

    状态转移方程:dp[i][j][k] = dp[i-1][j][k] + dp[i][j-1][k-a[i]];

    注意初始化条件,当j为0时,无论i,k取多少,方案数都为1,即无代码可写,那么我们都有1个方案,就是不派出程序员写代码。

    AC代码:(采用了滚动数组)

    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    #define maxn 505
    using namespace std;
    int dp[2][maxn][maxn];
    int ai[maxn];
    int main()
    {
        int n,m,b,mod;
        while(scanf("%d%d%d%d",&n,&m,&b,&mod) == 4){
            memset(dp,0,sizeof(dp));
            for(int i = 0;i <= 1;++i)
                for(int j = 0;j <= b;++j)
                    dp[i][0][j] = 1;
            for(int i = 1;i <= n;++i)
                scanf("%d",&ai[i]);
            for(int i = 1;i <= n;++i)
                for(int j = 1;j <= m;++j)
                    for(int k = 0;k <= b;++k){
                        dp[i & 1][j][k] = dp[(i - 1) & 1][j][k] % mod;
                        if(k - ai[i] >= 0) dp[i & 1][j][k] = (dp[i & 1][j][k] + dp[i & 1][j - 1][k - ai[i]]) % mod;
                    }
            printf("%d
    ",dp[n & 1][m][b] % mod);
        }
        return 0;
    }

    注意,有k<a[i]的情况。

  • 相关阅读:
    makefile
    xcode
    centos
    debug
    服务器开发
    socket
    xcode
    调用cpp库更基本
    nodejs cpp动态库
    html5图片裁剪法--
  • 原文地址:https://www.cnblogs.com/tiberius/p/6928142.html
Copyright © 2020-2023  润新知