zoukankan      html  css  js  c++  java
  • 暑假集训 || 动态规划

    ·背包问题:

    有很多的变式

    HDU 2546
    即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)
    首先拿出5元买最贵的东西,那接下来就是背包容量m-5,物品数量 n-1 的01背包问题了
    if(m<5)    cout<<m<<endl;
    else
    {
        int f[1010];//f[j]表示买前i件物品,预算为j时的最大花销
        memset(f,0,sizeof(f));
        for(int i=1; i<=n-1; i++)
            for(int j=m-5; j>=price[i]; j--)
                if(f[j]<f[j-price[i]]+price[i])
                    f[j]=f[j-price[i]]+price[i];
        cout<<m-max-f[m-5]<<endl;
    }
    View Code
    CodeForces 544C
    n个程序员要写m行程序,每个程序员在写一行程序时会产生ai个bug,写完m行共产生<=b个bug共有多少种方法
    完全背包问题f[i][j][k]表示第i个程序员写了j行产生k个bug的方法时
    f[i][j][k] = f[i-1][j][k] + f[i-1][j-1][k-a[i]] (考虑这个程序员这一行写或者不写)
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int f[550][550], a[550];
    int main()
    {
        int n, m, b, mod;
        scanf("%d %d %d %d", &n, &m, &b, &mod);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        f[0][0] = 1;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                for(int k = a[i]; k <= b; k++)
                    f[j][k] = (f[j][k] + f[j-1][k-a[i]]) % mod;
        int ans = 0;
        for(int i = 0; i <= b; i++) ans = (ans + f[m][i]) % mod;
        printf("%d
    ", ans);
        return 0;
    }
    View Code
    POJ 1837
    一个臂长15的天平,在不同位置有钩子,钩子上可以挂砝码,给你G个砝码,要把所有砝码都挂在钩子上,一共有多少种挂法
    f[i][j]表示挂了i个砝码,天平状态为j时的情况数,j=7500时表示平衡,j<7500向左倾斜,j>7500向右倾斜
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    typedef long long LL;
    #define SZ 20100
    int c[33], g[33];
    int f[33][SZ];
    int main()
    {
        int C, G;
        scanf("%d %d", &C, &G);
        for(int i = 0; i < C; i++) scanf("%d", &c[i]);
        for(int i = 1; i <= G; i++) scanf("%d", &g[i]);
        memset(f, 0, sizeof(f));
        for(int i = 0; i < C; i++) f[1][7500 + g[1]*c[i]] = 1;
        int ans = 0;
        for(int i = 2; i <= G; i++)
            for(int j = 0; j < 15000; j++)
                for(int k = 0; k < C; k++)
                    if(f[i-1][j] != 0)
                        f[i][j + g[i]*c[k]] += f[i-1][j];
        printf("%d
    ", f[G][7500]);
        return 0;
    }
    View Code
    HDU 4901
    题意:一个序列,取两个集合A和B,使得A集合中所有元素在B集合的左边,并且A集合中所有元素的异或值等于B集合中所有元素的and值,求满足条件的集合数量
    f[i][j]为前i个数异或值为j的方案数。g[i][j]为后i个数and值为j的方案数
    考虑到在中间的分割点可能重复选择,dp[i][j]表示后i个数且第i个数一定被选择的方案数
    然后乘法原理
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long LL;
    #define SZ 1010
    const LL mod = 1e9+7;
    LL f[SZ][1030], g[SZ][1030], dp[SZ][1030];
    int a[SZ];
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            int n;
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
            for(int i = 0; i <= n; i++)
                for(int j = 0; j <= 1024; j++)
                    f[i][j] = g[i][j] = dp[i][j] = 0;
            for(int i = 1; i < n; i++)
            {
                f[i][a[i]]++;
                for(int j = 0; j <= 1024; j++)
                    if(f[i-1][j])
                    {
                        f[i][j^a[i]] = (f[i][j^a[i]] + f[i-1][j]) % mod;
                        f[i][j] = (f[i][j] + f[i-1][j]) % mod;
                    }
            }
            for(int i = n; i > 1; i--)
            {
                g[i][a[i]]++;
                dp[i][a[i]]++;
                for(int j = 0; j <= 1024; j++)
                    if(g[i+1][j])//到i+1位时的方案数,i+1位可取可不取
                    {
                        g[i][j] = (g[i][j] + g[i+1][j]) % mod;//到i位时的方案数,i位不取
                        g[i][j&a[i]] = (g[i][j&a[i]] + g[i+1][j]) % mod;//到i位时的方案数,i位取
                        dp[i][j&a[i]] = (dp[i][j&a[i]] + g[i+1][j]) % mod;//到i位时的方案数,i位必须取
                    }
            }
            LL ans = 0;
            for(int i = 1; i < n; i++)
                for(int j = 0; j <= 1024; j++)
                    ans = (ans + f[i][j] * dp[i+1][j]) % mod;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【转】svn冲突问题详解 SVN版本冲突解决详解
    【转】Mysql解决The total number of locks exceeds the lock table size错误
    【转】iOS中修改AVPlayer的请求头信息
    【转】AJAX请求和普通HTTP请求区别
    【转】怎么给javascript + div编辑框光标位置插入表情文字等?
    【转】iOS开发笔记--识别单击还是双击
    【转】Android hdpi ldpi mdpi xhdpi xxhdpi适配详解
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
  • 原文地址:https://www.cnblogs.com/pinkglightning/p/9551492.html
Copyright © 2011-2022 走看看