poj 1837 balance DP 模拟赛 2017.10.10

来源:互联网 发布:淘宝发布食品如何备案 编辑:程序博客网 时间:2024/06/05 03:30

题目描述
有一个天平,天平左右两边各有若干个钩子,总共有 C 个钩子,有 G 个钩码,求将钩码全部挂到钩子上使天平平衡的方法的总数(∴数据保证钩码全挂上时才有可能达到平衡)。
输入描述
第一行两个数 c, g 分别代表钩子数和钩码数
第二行 c 个数,表示每个钩子距离天平中央的距离 c[i],
负数表示在左边,正数表示在右边
第三行 g 个数,表示每个钩码的重量 w[i]
输出描述
输出总方案数
样例输入
2 4
-2 3
3 4 5 8
样例输出
2
数据范围及提示
30%: c<=9, g<=9
100%: c<=20, g<=20, -15<=c[i]<=15, w[i]<=25

分析://初中物理:力矩的量纲是力×距离,∴保证两边力*距离的和相等即可//对于左边或右边,每个钩码有放或不放两种状态,每种方法会产生不同的影响//求方案数,∴考虑dp dp[i][j]:选取i个钩码,平衡度为j时的方案数//两个决定因素:必须平衡,平衡则必须用完所有的钩子,所以设计状态时考虑这两个,而且这两个因素受上一个选取了的钩子的影响,因为上一个选上了当前选取了的钩码数会+1,平衡度会变化,可以进行状态转移(递推) 最终所求状态:平衡,也就是左+右=0,所以定义一个平衡度为0 if <0偏左 , >0 偏右又因为数组下标不能为负数,最坏的情况就是都挂在左边或右边,此时 力矩=25*15*20=7500,也就是j∈[-7500,7500],又因为数组下标不能为负数,∴扩大一倍j∈[0,15000],平衡时,天平平衡度变为了7500\(^o^)/小优化:因为if语句,枚举第一遍时,dp都=0,但以后,就不一定了,也就是说,之前搜到的j状态下的dp一定=0,也就是第一遍搜的时候,之前没搜过,所以j状态一定没有出现过,所以一定=0 ∵i-1个不可能平衡 (数据保证钩码全挂上时才有可能达到平衡)∴没有必要搜,跳过   当i!=0的时候再继续往下搜,这样更快
#include<iostream>#include<cstdio> #include<cstring>using namespace std;int g,m,l[21],w[21],dp[21][15000];int main(){    //freopen("balance.in","r",stdin);    //freopen("balance.out","w",stdout);    scanf("%d%d",&g,&m);    for(int i=1;i<=g;i++) scanf("%d",&l[i]);    for(int i=1;i<=m;i++) scanf("%d",&w[i]);    memset(dp,0,sizeof(dp));    dp[0][7500]=1;//初始时状态只有一个,一个钩码也不挂,平衡    for(int i=1;i<=m;i++)        for(int j=0;j<=15000;j++)            if(dp[i-1][j])//=0 则跳过,小优化(见“分析”)            //!=0继续向下搜                for(int k=1;k<=g;k++)//枚举钩子的距离                    dp[i][j+w[i]*l[k]]+=dp[i-1][j];     printf("%d\n",dp[m][7500]);    return 0;}
原创粉丝点击