shu7-19【背包和母函数练习】

题目:http://acm.hdu.edu.cn/diy/contest_show.php?cid=20083

密码:shuacm

感觉他们学校的新生训练出的比较好。

今天很多题目都是强化了背包的转化。


关于背包转化成求最优解见分析:点击打开链接

贴个背包的模板:

//0-1背包, 代价为 cost, 获得的价值为 weight
// 每种物品最多只可以选一次
void ZeroOnePack(int cost, int weight)
{
    for(int i = nValue; i >= cost; i--)
        dp[i] = dp[i] + dp[i-cost]+weight;
}

// 完全背包,代价为 cost, 获得的价值为 weight
// 每种物品可以选无限次, 或者在可选的有限次内能够装满背包
void CompletePack(int cost, int weight)
{
    for(int i = cost; i <= nValue; i++)
        dp[i] = dp[i] + dp[i-cost]+weight;
}

//多重背包
//每种物品可以选有限次
void MultiplePack(int cost, int weight, int amount)
{
    if(cost*amount >= nValue) CompletePack(cost, weight);

    else
    {
        int k = 1;
        while(k < amount)
        {
            ZeroOnePack(k*cost, k*weight);
            amount -= k;
            k <<= 1;
        }
        ZeroOnePack(amount*cost, amount*weight);
    }
}


关于转化后,除掉 weight,把 max 换成 sum 即可,具体分析见上面的博客

void ZeroOnePack(int cost)
{
    for(int i = nValue; i >= cost; i--)
        dp[i] = dp[i] + dp[i-cost];
}

void CompletePack(int cost)
{
    for(int i = cost; i <= nValue; i++)
        dp[i] = dp[i] + dp[i-cost];
}

void MultiplePack(int cost, int amount)
{
    if(cost*amount >= nValue) CompletePack(cost);

    else
    {
        int k = 1;
        while(k < amount)
        {
            ZeroOnePack(k*cost);
            amount -= k;
            k <<= 1;
        }
        ZeroOnePack(amount*cost);
    }
}



           

A

和上面分析博客一样有木有

Problem A

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 40   Accepted Submission(s) : 32

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

"Well, it seems the first problem is too easy. I will let you know how foolish you are later." feng5166 says.

"The second problem is, given an positive integer N, we define an equation like this:
  N=a[1]+a[2]+a[3]+...+a[m];
  a[i]>0,1<=m<=N;
My question is how many different equations you can find for a given N.
For example, assume N is 4, we can find:
  4 = 4;
  4 = 3 + 1;
  4 = 2 + 2;
  4 = 2 + 1 + 1;
  4 = 1 + 1 + 1 + 1;
so the result is 5 when N is 4. Note that "4 = 3 + 1" and "4 = 1 + 3" is the same in this problem. Now, you do it!"

Input

The input contains several test cases. Each test case contains a positive integer N(1<=N<=120) which is mentioned above. The input is terminated by the end of file.

Output

For each test case, you have to output a line contains an integer P which indicate the different equations you have found.

Sample Input

4
10
20

Sample Output

5
42
627

#include
#include

const int maxn = 150;
int dp[maxn];

int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[0] = 1;
        for(int i = 1; i <= n; i++)
            for(int j = i; j <= n; j++)
                dp[j] += dp[j-i];
        printf("%d\n", dp[n]);

    }
    return 0;
}


B:母函数,待看中

为毛背包连样例 都 没有 出。。。感觉和 F 一样啊

Problem B

Time Limit : 1000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 23   Accepted Submission(s) : 18

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

又到了选课的时间了,xhd看着选课表发呆,为了想让下一学期好过点,他想知道学n个学分共有多少组合。你来帮帮他吧。(xhd认为一样学分的课没区别)

Input

输入数据的第一行是一个数据T,表示有T组数据。
每组数据的第一行是两个整数n(1 <= n <= 40),k(1 <= k <= 8)。
接着有k行,每行有两个整数a(1 <= a <= 8),b(1 <= b <= 10),表示学分为a的课有b门。

Output

对于每组输入数据,输出一个整数,表示学n个学分的组合数。

Sample Input

2
2 2
1 2
2 1
40 8
1 1
2 2
3 2
4 2
5 8
6 9
7 6
8 8

Sample Output

2
445

直接套用母函数模板,背包还是没有想出来。。。没道理啊

#include
#include

const int maxn = 1000000;
int c1[maxn];
int c2[maxn];

int a[10];
int b[10];

int main()
{
    int T;
    int n,k;
    scanf("%d", &T);
    while(T--)
    {
        memset(c1, 0, sizeof(c1));
        memset(c2, 0, sizeof(c2));
        c1[0] = 1;
        scanf("%d%d", &n,&k);
        for(int i = 1; i <= k; i++)
        {
            scanf("%d%d", &a[i],&b[i]);
        }

        for(int i = 1; i <= k; i++) //有几种学分, 第几层括号
        {
            for(int j = 0; j <= n; j++) //在原有的基础上遍历
            {
                for(int t = 0; t+j <= n && t <= a[i]*b[i]; t += a[i]) //遍历第 i 层括号的每一项
                {//每种学分选的次数有限制,所以同时 k 也不能超过当前总的
                    c2[t+j] += c1[j];
                }
            }

            for(int j = 0; j <= n; j++)
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        printf("%d\n", c1[n]);
    }
    return 0;
}



C :背包总容量改为总价值的一半,尽量装满背包。所求的最大体积则是第二个答案

        第一个答案 = 总价值-第一个答案

 注意:<= 0非法输入,跳出。而不是 n == -1 退出。         

Problem C

Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 39   Accepted Submission(s) : 11

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0

Input

Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 -- the total number of different facilities). The next N lines contain an integer V (0 A test case starting with a negative integer terminates input and this test case is not to be processed.

Output

For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.

Sample Input

2
10 1
20 1
3
10 1 
20 2
30 1
-1

Sample Output

20 10
40 40


#include
#include
#include
using namespace std;

const int maxn = 50*50*100+10;
int dp[maxn];
int nValue;

int v[60];
int m[60];

void ZeroOnePack(int cost)
{
    for(int i = nValue; i >= cost; i--)
        dp[i] = dp[i] + dp[i-cost];
}

void CompletePack(int cost)
{
    for(int i = cost; i <= nValue; i++)
        dp[i] = dp[i] + dp[i-cost];
}

void MultiplePack(int cost, int amount)
{
    if(cost*amount >= nValue) CompletePack(cost);

    else
    {
        int k = 1;
        while(k < amount)
        {
            ZeroOnePack(k*cost);
            amount -= k;
            k <<= 1;
        }
        ZeroOnePack(amount*cost);
    }
}

int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        if(n <= 0) break;
        int sum = 0;

        for(int i = 0; i < n; i++)
        {
            scanf("%d%d", &v[i], &m[i]);
            sum += v[i]*m[i];
        }
        nValue = sum/2;

        memset(dp,0,sizeof(dp));
        dp[0] = 1;

        for(int i = 0; i < n; i++)
        {
            MultiplePack(v[i], m[i]);
        }

        int ans1, ans2;
        for(int i = nValue; i >= 0 ; i--)
        {
            if(dp[i] != 0)
            {
                ans2 = i;
                break;
            }
        }
        ans1 = sum-ans2;
        printf("%d %d\n", ans1, ans2);
    }

    return 0;
}




D:完全背包

Problem D

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 25   Accepted Submission(s) : 20

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

People in Silverland use square coins. Not only they have square shapes but also their values are square numbers. Coins with values of all square numbers up to 289 (=17^2), i.e., 1-credit coins, 4-credit coins, 9-credit coins, ..., and 289-credit coins, are available in Silverland. 
There are four combinations of coins to pay ten credits: 

ten 1-credit coins,
one 4-credit coin and six 1-credit coins,
two 4-credit coins and two 1-credit coins, and
one 9-credit coin and one 1-credit coin. 

Your mission is to count the number of ways to pay a given amount using coins of Silverland.

Input

The input consists of lines each containing an integer meaning an amount to be paid, followed by a line containing a zero. You may assume that all the amounts are positive and less than 300.

Output

For each of the given amount, one line containing a single integer representing the number of combinations of coins should be output. No other characters should appear in the output. 

Sample Input

2
10
30
0

Sample Output

1
4
27


#include
#include
#include
using namespace std;

int dp[310];
int a[20];
int nValue;

void CompletePack(int cost)
{
    for(int i = cost; i <= nValue; i++)
        dp[i] = dp[i] + dp[i-cost];
}

int main()
{
    while(scanf("%d", &nValue) != EOF)
    {
        if(nValue == 0) break;
        for(int i = 1; i <= 17; i++)
            a[i] = i*i;
        memset(dp,0,sizeof(dp));
        dp[0] = 1;

        for(int i = 1; i <= 17; i++)
            CompletePack(a[i]);
        printf("%d\n", dp[nValue]);
    }
}


E:不会

Problem E

Time Limit : 30000/15000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 4   Accepted Submission(s) : 1

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

Mr. B loves to play with colorful stones. There are n colors of stones in his collection. Two stones with the same color are indistinguishable. Mr. B would like to 
select some stones and arrange them in line to form a beautiful pattern. After several arrangements he finds it very hard for him to enumerate all the patterns. So he asks you to write a program to count the number of different possible patterns. Two patterns are considered different, if and only if they have different number of stones or have different colors on at least one position.

Input

Each test case starts with a line containing an integer n indicating the kinds of stones Mr. B have. Following this is a line containing n integers - the number of 
available stones of each color respectively. All the input numbers will be nonnegative and no more than 100.

Output

For each test case, display a single line containing the case number and the number of different patterns Mr. B can make with these stones, modulo 1,000,000,007, 
which is a prime number.

Sample Input

3
1 1 1
2
1 2

Sample Output

Case 1: 15
Case 2: 8

Hint

In the first case, suppose the colors of the stones Mr. B has are B, G and M, the different patterns Mr. B can form are: B; G; M; BG; BM; GM; GB; MB; MG; 
BGM; BMG; GBM; GMB; MBG; MGB.


F:多重背包求解

Problem F

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 79   Accepted Submission(s) : 23

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

We all know that Bin-Laden is a notorious terrorist, and he has disappeared for a long time. But recently, it is reported that he hides in Hang Zhou of China! 
“Oh, God! How terrible! ”



Don’t be so afraid, guys. Although he hides in a cave of Hang Zhou, he dares not to go out. Laden is so bored recent years that he fling himself into some math problems, and he said that if anyone can solve his problem, he will give himself up! 
Ha-ha! Obviously, Laden is too proud of his intelligence! But, what is his problem?
“Given some Chinese Coins (硬币) (three kinds-- 1, 2, 5), and their number is num_1, num_2 and num_5 respectively, please output the minimum value that you cannot pay with given coins.”
You, super ACMer, should solve the problem easily, and don’t forget to take $25000000 from Bush!

Input

Input contains multiple test cases. Each test case contains 3 positive integers num_1, num_2 and num_5 (0<=num_i<=1000). A test case containing 0 0 0 terminates the input and this test case is not to be processed.

Output

Output the minimum positive value that one cannot pay with given coins, one line for one case.

Sample Input

1 1 3
0 0 0

Sample Output

4


#include
#include
#include
using namespace std;

const int maxn = 8000+10;
int dp[maxn];
int nValue;

void ZeroOnePack(int cost)
{
    for(int i = nValue; i >= cost; i--)
        dp[i] = dp[i] + dp[i-cost];
}

void CompletePack(int cost)
{
    for(int i = cost; i <= nValue; i++)
        dp[i] = dp[i] + dp[i-cost];
}

void MultiplePack(int cost, int amount)
{
    if(cost*amount >= nValue) CompletePack(cost);

    else
    {
        int k = 1;
        while(k < amount)
        {
            ZeroOnePack(k*cost);
            amount -= k;
            k <<= 1;
        }
        ZeroOnePack(amount*cost);
    }
}

int main()
{
    int a,b,c;
    while(scanf("%d%d%d", &a,&b,&c) != EOF)
    {
        if(a == 0 && b == 0 && c == 0) break;

        memset(dp,0,sizeof(dp));
        dp[0] = 1;
        nValue = 1*a+2*b+5*c;

        MultiplePack(1, a);
        MultiplePack(2, b);
        MultiplePack(5, c);

        for(int i = 0; i < maxn; i++)
        {
            if(dp[i] == 0)
            {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}

G:签到。。。

Problem G

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 45   Accepted Submission(s) : 40

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事,你们一定都觉得这猴子太闹腾了,其实你们是有所不知:悟空是在研究一个数学问题!
什么问题?他研究的问题是蟠桃一共有多少个!
不过,到最后,他还是没能解决这个难题,呵呵^-^
当时的情况是这样的:
第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。聪明的你,请帮悟空算一下,他第一天开始吃的时候桃子一共有多少个呢?

Input

输入数据有多组,每组占一行,包含一个正整数n(1

Output

对于每组输入数据,输出第一天开始吃的时候桃子的总数,每个测试实例占一行。

Sample Input

2
4

Sample Output

4
22

Statistic |  Submit |  Back

#include

int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        int ans = 1;
        while(--n)
        {
            ans = (ans+1)*2;
        }
        printf("%d\n", ans);
    }
    return 0;
}





你可能感兴趣的:(acm,解题报告,模板总结,DP之背包问题)