希望的海洋

Ain't about how fast I get there,ain't about what's waiting on the other side

常用链接

统计

最新评论

背包系列——poj 1837

题意:
就是说一个天平,给了C个距离(坐标),G个砝码,问砝码全用上,有几种让它平衡的办法。
dp[i][j]表示在挂上前i个物体的时,平衡度为j(j>0时表示左边重,j=0时表示天平平衡,j<0时表示右边重)时挂法的数量,而根据题意可以确定j的取值范围为:[-7500,7500],于是可以得到状态转移方程为:
       dp[i][j]+=(dp[i-1][j-p[k]*g[i]]),    p[k]表示第k个挂钩的位置,g[i]为第i个砝码的重量

    由于j-p[k]*g[i]可能为负数,因此统一加上7500,那么初始状态dp[0][7500]=1(此时表示天平平衡),表示不用物体且使得天平平衡时的方法只有一种.

// (1)用二维数组 的 01背包 解。一个一个砝码往上放,头开始 is[0][7500]=1,指0个砝码时为平衡7500,此时有一种方法。
#include<cstdio>
#include
<cstdlib>
#include
<cmath>
#include
<string>
int wi[26],dis[26],is[26][15005],C,G;//力矩的极值为-7500,7500.下标为正,故计算时+7500
void ZeroOnepack()
{
    
int i=0,j,k;
    
//for(i=1;i<=G;i++)
 
//   {
 
//       for(j=-7500;j<=7500;j++)
 
//        for(k=1;k<=C;k++)
 
//         //if(j+7500>=dis[k]*wi[i])
 
//           is[i][j+7500]+=is[i-1][j+7500-dis[k]*wi[i]];
 
//   }
    for(i=1;i<=G;i++)
    
{
        
for(j=-7500;j<=7500;j++)
         
for(k=0; k < C;k++)
          
//if(j+7500>=dis[k]*wi[i])
            is[i][j+7500]+=is[i-1][j+7500-dis[k]*wi[i-1]];//考虑放第i个砝码时的情况数,在第i-1个砝码上加。
    }


}

int main()
{

    
int i=0,tem=0,yz,neg,ws=0,a=1,b=1;
    scanf(
"%d%d",&C,&G);
    
//for(i=1;i<=C;++i)
    
//{
    
//    scanf("%d",&dis[i]);
    
//}
    
//for(i = 1 ; i <= G ; ++i    )
    
//{
    
//        scanf("%d",&wi[i]);
    
//}
    for(i=0;i<C;++i)
    
{
        scanf(
"%d",&dis[i]);
    }

    
for(i = 0 ; i < G ; ++i    )
    
{
            scanf(
"%d",&wi[i]);
    }

    memset(
is,0,sizeof(is)/sizeof(int));
        
is[0][7500]=1;
        ZeroOnepack();
        printf(
"%d\n",is[G][7500]);
        
return 0;
}
2)用一维数组 01背包 解。须用2个一维数组以保证一个物体只能用一次,
因为:假如说只用到f这个数组,不用两个:那么讨论到第i个物体的时候,
f[j]是一个用了i这个物体来达到的状态,但是你f[k]是用f[j]来转移并且用上i的话,
这样f[k]就用了两次i了。二维数组就可以避免这种重复使用,或者用两个一维
数组,每次保证累加时使用的都是没用i时的:当我讨论到i这个物体的时候,先
把之前没讨论到i的状态先存下来,这样每到达一个新状态,都是用没有用到i的
状态tp来转移的,这样的新状态都是用了一次i

//2)用一维数组 01背包 解。须用2个一维数组以保证一个物体只能用一次,
//因为:假如说只用到f这个数组,不用两个:那么讨论到第i个物体的时候,
//f[j]是一个用了i这个物体来达到的状态,但是你f[k]是用f[j]来转移并且用上i的话,
//这样f[k]就用了两次i了。二维数组就可以避免这种重复使用,或者用两个一维
//数组,每次保证累加时使用的都是没用i时的:当我讨论到i这个物体的时候,先
//把之前没讨论到i的状态先存下来,这样每到达一个新状态,都是用没有用到i的
//状态tp来转移的,这样的新状态都是用了一次i
#include<cstdio>
#include
<string>
#include
<iostream>
#include
<cstdlib>

int dp[15002],tp[15002],C,G;

int main()
{
    
int i,j,k,pos[26],wi[26];
    scanf(
"%d%d",&C,&G);
    
for(i=0;i<C;++i)
        scanf(
"%d",&pos[i]);
    
for(i=0;i<G;++i)
        scanf(
"%d",&wi[i]);
    dp[
7500]=1;
    
for(i=0;i<G;++i)
        
{
            memcpy(tp,dp,
sizeof(dp));
            memset(dp,
0,sizeof(dp));
            
for(j=-7500;j<=7500;j++)
                
for(k=0;k<C;++k)
                    dp[j
+7500]+=tp[j+7500-pos[k]*wi[i]];
    }

            printf(
"%d\n",dp[7500]);
    
return 0;

}

posted on 2011-08-02 08:34 拥梦的小鱼 阅读(942) 评论(1)  编辑 收藏 引用 所属分类: POJ

评论

# re: 背包系列——poj 1837 2012-01-24 15:17 wyc4662

滚动数组的话可以只用一个一维数组,你把to改成downto就能解决问题  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理