码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ 2955 Interesting Dart Game(完全背包+鸽巢原理)

时间:2015-04-08 21:35:21      阅读:273      评论:0      收藏:0      [点我收藏+]

标签:zoj   背包   完全背包   

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1954


Recently, Dearboy buys a dart for his dormitory, but neither Dearboy nor his roommate knows how to play it. So they decide to make a new rule in the dormitory, which goes as follows:

Given a number N, the person whose scores accumulate exactly to N by the fewest times wins the game.

Notice once the scores accumulate to more than N, one loses the game.

Now they want to know the fewest times to get the score N.

技术分享

So the task is : 
Given all possible dart scores that a player can get one time and N, you are required to calculate the fewest times to get the exact score N.

Input

Standard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 50) which is the number of test cases. And it will be followed byT consecutive test cases.

Each test case begins with two positive integers M(the number of all possible dart scores that a player can get one time) and N.  Then the following M integers are the exact possible scores in the next line.

Notice: M (0 < M < 100), N (1 < N <= 1000000000), every possible score is (0, 100).

Output

For each test case, print out an integer representing the fewest times to get the exact score N.
If the score can‘t be reached, just print -1 in a line.

Sample Input

3
3 6
1 2 3
3 12
5 1 4
1 3
2

Sample Output

2
3
-1


Author: WANG, Yijie
Source: Zhejiang University Local Contest 2008


题意:http://www.cnblogs.com/K-R-Q/archive/2011/12/21/2296035.html


http://zeming89.blog.163.com/blog/static/5739380420107164303521/

题yi:给定m,0<m<100,个数字w[],0<wi<100,求数字组合成 N (1 < N <= 1000000000) 的最小组合数,
即:N = a1*w1 + a2*w2 + ... + am*wm, 求 a1+a2+...+am的和最小
分析:题目看上去就是一个完全背包问题,但因为 N 的数据量是10亿,因此肯定是计算用的而不能直接用于
背包容量,因此需要优化。
鸽巢定义应用:可以先将 w[] 排序,可以想到
a1
a1+a2
a1+a2+a3
...
a1+a2+a3+...+a(n-1)(!!)(用%an去想,就是有an个鸽巢)
这个东西,就是说如果 选用 小于an 的数字超过 an个 (m>an) (!!),那就会出现某个子集是an的倍数,
直接可以用an表示掉(第二次应用,要记住了)
回到题目,所以对于最大的 w[i],它能承受的子集和是 w[i]*w[i](这里有所放宽,但最大都为100*100,
可以让dp接受,没有问题),所以就可以开一个10000的数组做dp了。

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 10000
int dp[maxn+147];
int w[147];
int M, N;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&M,&N);
        for(int i = 1; i <= M; i++)
        {
            scanf("%d",&w[i]);
        }
        sort(w+1, w+M+1);
        int cnt = 0;
        if(N > maxn)//鸽巢原理
        {
            int tt = (N-maxn)%w[M]+maxn;
            cnt = (N-tt)/w[M];
            N = tt;
        }
        
        memset(dp,INF,sizeof(dp));
        dp[0] = 0;
        for(int i = 1; i <= M; i++)
        {
            for(int j = w[i]; j <= N; j++)
            {
                dp[j] = min(dp[j],dp[j-w[i]]+1);
            }
        }
        if(dp[N] == INF)
        {
            printf("-1\n");
            continue;
        }
        int ans = dp[N]+cnt;
        printf("%d\n",ans);
    }
    return 0;
}



ZOJ 2955 Interesting Dart Game(完全背包+鸽巢原理)

标签:zoj   背包   完全背包   

原文地址:http://blog.csdn.net/u012860063/article/details/44946667

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!