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\n", 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\n", dp[cur][10000]);

    }

    return 0;
}
时间: 2024-10-08 17:57:45

poj 1837 Balance 动态规划的相关文章

poj 1837 Balance 动态规划 (经典好题,很锻炼思维)

题目大意:给你一个天平,并给出m个刻度,n个砝码,刻度的绝对值代表距离平衡点的位置,并给出每个砝码的重量.达到平衡状态的方法有几种. 题目思路:首先我们先要明确dp数组的作用,dp[i][j]中,i为放置的砝码数量,j为平衡状态,0为平衡,j<0左倾,j>0右倾,由于j作为下标不能是负数,所以我们要找一个新的平衡点,因为15*20*20 = 7500,所以平衡点设置为7500, 然后我们可以得出动态方程 dp[i][j+w[i]*c[k])+=dp[i-1][j]; #include<c

POJ 1837 Balance

题意:给你C个挂钩,W个钩码,要你能使一个天平平衡 数据解释: 2 4 -2 3 3 4 5 8 以原点为支点,那么-2代表支点左边2处有一个钩码,同理3代表右边的点 所以案例数据有一个成立的例子是(3+5)*3=(4+8)*2或是(3+4+5)*2=8*3(力臂平衡) 有2种情况所以输出2: 思路:这个如果不是按照题目的分类说是DP我还想不到这个思路,我感觉我进步挺大了,能独立推出转移方程了. 首先我们看这道题首先是要求力平衡,那么一个限制是重量.与力相关的有钩码与挂钩的位置.显然,钩码可以放

poj 1837 Balance (dp,01背包)

链接:poj 1837 题意:有一个天平,天平左右两边各有若干个钩子,总共有C个钩子,有G个钩码, 求将钩码挂到钩子上使天平平衡的方法的总数.其中可以把天枰看做一个以x轴0点作为平衡点的横轴 分析:力臂=重量 *臂长 = g[i]*c[j] 当平衡度k=0时,说明天枰达到平衡,k>0,说明天枰倾向右边(x轴右半轴),k<0则左倾 因此可以定义一个 状态数组dp[i][k],意为在挂满前i个钩码时,平衡度为k的挂法的数量. 由于距离c[i]的范围是-15~15,钩码重量的范围是1~25,钩码数量

poj 1837 Balance(背包)

题目链接:http://poj.org/problem?id=1837 Balance Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 10983   Accepted: 6824 Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different from any other

POJ 1837 Balance(动态规划之背包问题)

Balance Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11436   Accepted: 7130 Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different from any other ordinary balance. It orders two arms

POJ 1837 Balance (多重背包计数)

Balance Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11706   Accepted: 7305 Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different from any other ordinary balance. It orders two arms

POJ 1837 Balance 背包dp

点击打开链接 Balance Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11067   Accepted: 6865 Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different from any other ordinary balance. It orders t

POJ 1837 Balance DP

Balance Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 10299   Accepted: 6372 Description Gigel has a strange "balance" and he wants to poise it. Actually, the device is different from any other ordinary balance. It orders two arms

poj 1837 Balance (0 1 背包)

Balance Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 10326   Accepted: 6393 题意:给你n个挂钩g个砝码  以及n个挂钩的距离天平中心距离(负的代表左边正的代表右边)g个砝码的重量. 要求输出能够令天平平衡的方法种类 解题思路     http://user.qzone.qq.com/289065406/blog/1299341345  非常具体 #include<iostream> #i