• poj 1837 Balance 动态规划


    题目链接:http://poj.org/problem?id=1837

    使用迭代器对STL容器进行遍历的方法:

    for(set<int>::iterator it = check.begin(); it != check.end(); it++)

    {

      //...*it

    }

     

    本题

    a[]存挂钩位置

    b[]存物品质量

    把挂在天平左边的物品的质量视为负数 反之为正数

    总质量的极限为20件重25的物品都挂在15的天平挂钩处 即7500

    dp[i][j]表示前i件物品总质量为(j-10000)时的挂法总数【数组下标不能为负 所以整体往右移10000】

    前i件的状态至于前i-1件有关 所以用滚动数组来作dp

    裸的dp思想如下:

    memset(dp, 0, sizeof(dp));//初始化
    dp[0][10000] = 0;//初始条件

    for i = 0...g
        for k = 0...20000
            if dp[cur][k] != 0 //保证下面的for循环中 dp数组的第二维的下标不为负数
                for j = 0...c
                    dp[i][k + b[i]*a[j]] += dp[i-1][k];//把重b[i]的物品放a[j]处后 用原状态dp[i-1][k]的值来不断更新现状态

    以上过程稍加改动即变为滚动数组实现

    复杂度:20 * 30 * 20000  约10^7

    不同于许多别人的博客

    个人认为这只是一道“类01背包”的问题 而不像别人所说的“就是01背包”

    之前对背包问题的理解有误

    看了背包九讲的目录之后才发现

    “每种物品最多只能放一次”就可以往01背包想了

    个人觉得

    背包问题不仅旨在解决求最大价值的问题

    它更广泛的意义在于 为关于“选物品”之类的问题提供了一种合适的操作模式

    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #include <set>
    #include <queue>
    #include <vector>
    
    using namespace std;
    
    const int maxn = 25;
    const int maxm = 20000;
    int dp[2][maxm];
    
    int a[maxn];
    int b[maxn];
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
    
        int c, g;
        while(scanf("%d%d", &c, &g) == 2)
        {
            for(int i = 0; i < c; i++)
                scanf("%d", &a[i]);
            for(int i = 0; i < g; i++)
                scanf("%d", &b[i]);
    
            int cur = 0;
            dp[cur][10000] = 1;
    
            for(int i = 0; i < g; i++)
            {
                memset(dp[cur^1], 0, sizeof(dp[cur]));
                for(int t = 0; t < 20000; t++)
                {
                    if(dp[cur][t])
                    {
                        for(int j = 0; j < c; j++)
                        {
                            int tmp = t + b[i]*a[j];
    
                            dp[cur^1][tmp] += dp[cur][t];
    
                        }
                    }
                }
                cur = cur ^ 1;
            }
    
            printf("%d
    ", dp[cur][10000]);
    
        }
    
    
    
        return 0;
    }

    最后我想吐槽一个事

    stl要慎用

    本来想着在枚举20000个总质量的时候用set记录出现过的总质量 来做个优化

    没想到时间反而变成原来的50倍!

    感觉stl在写大模拟的时候好用

    然后像这种题还是少用吧

    上面的代码16MS 下面的代码750MS

    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #include <set>
    #include <queue>
    #include <vector>
    
    using namespace std;
    
    const int maxn = 25;
    const int maxm = 20000;
    int dp[2][maxm];
    
    int a[maxn];
    int b[maxn];
    set<int> check[2];
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
    
        int c, g;
        while(scanf("%d%d", &c, &g) == 2)
        {
            check[0].clear();
            check[1].clear();
    
            for(int i = 0; i < c; i++)
                scanf("%d", &a[i]);
            for(int i = 0; i < g; i++)
                scanf("%d", &b[i]);
    
            int cur = 0;
            dp[cur][10000] = 1;
            check[cur].insert(10000);
    
            for(int i = 0; i < g; i++)
            {
                memset(dp[cur^1], 0, sizeof(dp[cur]));
                for(set<int>::iterator it = check[cur].begin(); it != check[cur].end(); it++)
                {
                    for(int j = 0; j < c; j++)
                    {
                        int tmp = *it + b[i]*a[j];
    
                        dp[cur^1][tmp] += dp[cur][*it];
    
                        check[cur^1].insert(tmp);
                    }
    
    
                }
                check[cur].clear();
                cur = cur ^ 1;
            }
    
            printf("%d
    ", dp[cur][10000]);
    
        }
    
    
    
        return 0;
    }
  • 相关阅读:
    linux学习笔记-11.正则表达式
    linux学习笔记-10.解压与压缩
    linux学习笔记-9.查找
    linux学习笔记-8.vim
    linux学习笔记-7.文件属性
    linux学习笔记-6.权限
    linux学习笔记-5.用户和组
    @Param注解的用法解析
    linux学习笔记-4.系统命令
    linux学习笔记-3.文件相关命令
  • 原文地址:https://www.cnblogs.com/dishu/p/4293353.html
Copyright © 2020-2023  润新知