zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    yolo_to_onnx ValueError: need more tan 1 value to unpack
    yolo_to_onnx killed
    C++ 实现二维矩阵的加减乘等运算
    Leetcode 1013. Partition Array Into Three Parts With Equal Sum
    Leetcode 1014. Best Sightseeing Pair
    Leetcode 121. Best Time to Buy and Sell Stock
    Leetcode 219. Contains Duplicate II
    Leetcode 890. Find and Replace Pattern
    Leetcode 965. Univalued Binary Tree
    Leetcode 700. Search in a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/dishu/p/4293353.html
Copyright © 2011-2022 走看看