POJ 1837 Balance 题解

原题链接

题意略(来日再补)

分析:
用动态规划解此题
dp[i][j] 表示只使用(且必须使用)前i个钩码,达到偏移量(该名词为童鞋自创,由SYX保留专利权 ╮(╯▽╰)╭ )为j的方法数。下面介绍一下“偏移量”:
由天平右边的所有砝码分别乘以其力矩得到的右偏移量之和,加上左偏移量之和(这是个非正数)。(这个解释不造你能不能看懂嘿 T_T|| ) 下面上例子
假如有个天平现在的状态是

那么它的左偏移量为:(-3) * 1 + (-1) * 3 = -6
同理右偏移量为: 8
所以它的总偏移量为 8 - 6 = 2
那么当总偏移量为0时,天平平衡(这是显然的 ( * ^__^ * ) 嘻嘻……)。
那么有动态转移方程
dp[i][k]+=dp[i-1][k-dist[j]*weig[i]]
其中k from 0 to 15000
再来说说15000是怎么来的

The input has the following structure:
• the first line contains the number C (2 <= C <= 20) and the number G (2 <= G <= 20);
• the next line contains C integer numbers (these numbers are also distinct and sorted in ascending order) in the range -15..15 representing the repartition of the hooks; each number represents the position relative to the center of the balance on the X axis (when no weights are attached the device is balanced and lined up to the X axis; the absolute value of the distances represents the distance between the hook and the balance center and the sign of the numbers determines the arm of the balance to which the hook is attached: ‘-’ for the left arm and ‘+’ for the right arm);
• on the next line there are G natural, distinct and sorted in ascending order numbers in the range 1..25 representing the weights’ values.

由题中的数据范围可以算出一边的最大偏移量为7500(从SXY童鞋那里借来的数字),所以两边最大差15000。别问我为什么要乘2,因为数组下标不能为负,所以左边的要向右移7500位,当然右边的就被挤跑了,于是请开一个15001的数组。
然后就没有然后了,就剩下代码实现了。

#include<iostream>//01背包--共有g个物体,如何选取能够使占用总体积为0,求出总方案数;
#include<cmath>
#include<cstring> 
#include<algorithm>
using namespace std;
int main(){
    int c,g;//c--钩子数;g--砝码数; 
    cin>>c>>g;
    int dist[c+1],weig[g+1];//dist--distance;weig--weight;
    for(int i=1;i<=c;i++)
        cin>>dist[i];
    for(int i=1;i<=g;i++)
        cin>>weig[i];
    int f[g+1][15001];//f[i][j]代表选取前i个物品,偏移量为j的最大方案数--因为g(max)*c(max)*wei(max)=7500,7500*2=15000;
    memset(f,0,sizeof(f));
    f[0][7500]=1;
    for(int i=1;i<=g;i++)//第i个物体(必须挂) 
        for(int j=1;j<=c;j++)//放在j位置 
            for(int k=0;k<=15000;k++){//偏移量 
                int x=k-dist[j]*weig[i];//防止越界 
                if(x<0)
                    continue;
                else
                    f[i][k]+=f[i-1][x];//f[i][k]可以由它的上一个状态转移而来 
            }
    cout<<f[g][7500]<<endl;
    return 0; 
}

感谢SYX童鞋洋溢着浓厚的注释氛围的代码(别问我为啥不放我的,因为我的代码没存着)。另外说一下,这个算法时间复杂度是O(n^2)的,别看有三重循环,但是最内层循环只是个常数(虽然看起来挺大的说)。没记错的话应该是63MS AC,所以时间没问题。

By YOUSIKI

你可能感兴趣的:(dp,动态规划,poj)