背包系列——poj 1837

背包系列——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;

}

你可能感兴趣的:(背包系列——poj 1837)