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

题目链接: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;
}
时间: 2024-07-29 15:13:48

ZOJ 2955 Interesting Dart Game(完全背包+鸽巢原理)的相关文章

鸽巢原理简单应用

http://poj.org/problem?id=2356 从n个数里面取出一些数,这些数的和是n的倍数.并输出这些数. 先预处理出前n个数的和用sum[i]表示前i个数的和.若某个sum[i]是n的倍数,直接输出前i个数即可. 否则说明n个数中对n取余的结果有n-1种,即余数为(1~n-1),根据鸽巢原理知必定至少存在两个sum[i]与sum[j]对n取余的结果相等.那么i+1 ~ j之间的数之和一定是n的倍数. #include <stdio.h> #include <iostre

poj 2356 Find a multiple 鸽巢原理的简单应用

题目要求任选几个自然数,使得他们的和是n的倍数. 由鸽巢原理如果我们只选连续的数,一定能得到解. 首先预处理前缀和模n下的sum,如果发现sum[i]==sum[j] 那么(sum[j]-sum[i])%n一定为0,直接输出i+1~j就够了. 为什么一定会有解,因为sum从1~n有n个数,而模n下的数只有0~n-1,把n个数放入0~n-1个数里,怎么也会有重复,所以这种构造方法一定没问题. 其实可以O(n)实现,嫌麻烦,就二重循环无脑了. #include <iostream> #includ

鸽巢原理-poj3370

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <stdio.h> int main(int argc, char *argv[]) {         int c = -1, n = -1;         while (true) {         scanf("%d%d",

骚操作之鸽巢原理

桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面至少放两个苹果.这一现象就是我们所说的"抽屉原理". 抽屉原理的一般含义为:"如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素." 抽屉原理有时也被称为鸽巢原理.它是组合数学中一个重要的原理. 在acm中也是会遇到的,比如两个人对打的得分问题 110个人参加一个国际象棋单循环比赛,每两人都进行一局比赛,

HDU 1205.吃糖果【鸽巢原理】【8月1】

吃糖果 Problem Description HOHO,终于从Speakless手上赢走了所有的糖果,是Gardon吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一种,这样:可是Gardon不知道是否存在一种吃糖果的顺序使得他能把所有糖果都吃完?请你写个程序帮忙计算一下. Input 第一行有一个整数T,接下来T组数据,每组数据占2行,第一行是一个整数N(0<N<=1000000),第二行是N个数,表示N种糖果的数目Mi(0<Mi<=10000

POJ 2356 Find a multiple 鸽巢原理

题目来源:POJ 2356 Find a multiple 题意:n个数 选出任意个数 使得这些数的和是n的倍数 思路:肯定有解 并且解是连续的一段数 证明: 假设有m个数 a1,a2,a3...am    s1 s2 s3...sm为前缀和 s1 = a1 s2 = a1+a2 s3 = a1+a2+a3... sm = a1+a2+a3+...+am 1.如果某个前缀和si%m == 0 那么得到解 2.设x1=s1%m x2 = s2%m x3 = s3%m xm = sm%m 因为1不成

HDU3183(RMQ+鸽巢原理)

题目的意思是对于一个n位数,删除m个位后,得到的最小数是什么,比如12345 2,删除两个位,得到最小的就是123.实际上这题目解法很多,好像有贪心,线段树,RMQ等,因为我最近在学习RMQ,所以就用RMQ了. 这题目用了一个鸽巢原理,得到的m-n位数的第一位,必然出现在1~m-n+1,这个由鸽巢原理就十分明显了(如果1~n-(m-n)+1都没有的话,剩下的m-n-1个位是不可能凑出m-n个位的数的!)这样我们就可以从[1,n-(m-n)+1]中作RMQ取得最小值下标i,之后对于i+1后,m-n

鸽巢原理

鸽巢原理: n+1个鸽子放入n个窝中,至少有一个窝含有两只鸽子  Find a multiple Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5590   Accepted: 2434   Special Judge Description The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that

POJ 2356. Find a multiple 抽屉/鸽巢原理

Find a multiple Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7192   Accepted: 3138   Special Judge Description The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers is not greater than 15000