首页 > ACM题库 > HDU-杭电 > Hdu 1786 Tempter of the Bone again-背包问题[解题报告] C++
2013
12-23

Hdu 1786 Tempter of the Bone again-背包问题[解题报告] C++

Tempter of the Bone again

问题描述 :

Ignatius found some bones in an ancient maze, which fascinated him a lot. However, when he picked them up, the maze began to shake, and Ignatius could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze.
Suddenly, Ignatius heard a very very cool voice, and he recognize that it comes from Beelzebub feng5166:“I know that you like bone, and even I know your nick name is wishingbone. Today, I give you a chance to survive: there are N kinds of bones here and the number of each kind bone is enough, their weights are Wi pounds (1<=i<=N), your bag has a volume of M pounds, and I also know that you will spend 3 seconds time when you pick up any one bone. Today, you must fill up your bag as quick as you can, otherwise, the maze is your place of the death!”.
Oh, my god! Can the poor Ignatius survive? Please help him!
Note: You are guarantied that solution always exist for every test case.

输入:

The input consists of multiple test cases. The first line of each test case contains two integers N and M (1 < N < 10; 0 < M < 1000000000), which denote the kinds of the bone and the capacity of the bag respectively. The next line give N integers W1…Wn (1<=wi<=100), which indicate the weights of bones
The input is terminated with two 0′s. This test case is not to be processed.

输出:

For each test case, print the minimal time Ignatius will spend when he can survive. One line per case.

样例输入:

2 20
1 5
0 0

样例输出:

12

题目意思:把包放满至少需要几个东西,每个东西数量足够。

第一感觉就是背包问题。由于容量最高10亿,把这个作为背包就不现实了,但发现物品种类最多9个,而且重量上限只有100,于是考虑从这里入手。但不知怎么回事,草稿打着打着灵感一来用了递归。搞一个函数ans(x,y);返回x的容量从第y件物品开始放最少需要几件,物品先递减排序。

需要得到的结果自然是ans(背包容量,0);

函数里面:

如果这件物品能放满直接返回x除以第y件物品的价值

如果不能且接下去没有物品了返回-1

走到这一步说明不能放满,还有余数,且接下去还有更小的物品,那就得到一个ans(x%value[y],y+1)。

但这样不一定能得到答案啊,比如说12容量的背包,物品价值有5、3,先放了5,还余2,那3就放不了了,但答案就是3的价值放4次啊。

那怎么办呢?本来只考虑5放2次的情况,那我把5放0~2次的情况都考虑遍,取最小值就好了。

最后还有个问题,(10亿-1)的背包里放价值5可放(2亿-1)次,都考虑过来明显不行。

这个就要看接下来那个数了,比如说接下来的数是3,我只要考虑5最多少放(3-1)次即可,为什么呢?当时感觉就这样=。=,说不清楚,就是这里原以为会WA,结果居然AC了。

感觉跟余数什么的有关,求解释!!

#include<iostream>
int N,M,W[10];
int cmp(const void *a,const void *b){
    return *(int *)b-*(int *)a;
}
int f_min(int x,int y){
if(x==-1)return y;
return x<y?x:y;
}
void get_W(){
    int i;
    for(i=0;i<N;i++)
        scanf("%d",&W[i]);
    qsort(W,N,sizeof(int),cmp);
}
int ans(int bag,int s){
    int w=W[s],up;
    if(bag%w==0)return bag/w;
    if(s==N-1)return -1;
    up=bag/w;
    int lim=f_min(up,W[s+1]-1),i,min=-1,temp;
    for(i=0;i<=lim;i++){
        temp=ans(bag%w+i*w,s+1);
        if(temp==-1)continue;
        min=f_min(min,up-i+temp);
    }
    return min;
}
int main(){
    while(scanf("%d%d",&N,&M)&&(N||M)){
        get_W();
        printf("%d/n",3*ans(M,0));
    }
    return 0;
}