1. 程式人生 > 實用技巧 >幾道揹包題

幾道揹包題

Bone Collector

描述

傳送門:Bone Collector

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

輸入

The first line contain a integer T , the number of cases. Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

輸出

One integer per line representing the maximum of the total value (this number will be less than 231).

樣例

輸入

1

5 10

1 2 3 4 5

5 4 3 2 1

輸出

14

程式碼

 1 /*
 2  * =========================================================================
 3  *
 4  *       Filename:  2602.cpp
 5  *
 6  *           Link:  
http://acm.hdu.edu.cn/showproblem.php?pid=2602 7 * 8 * Version: 1.0 9 * Created: 2018/07/11 11時44分51秒 10 * Revision: none 11 * Compiler: g++ 12 * 13 * Author: 杜寧元 (https://duny31030.github.io/), [email protected] 14 * Organization: QLU_浪在ACM 15 * 16 * ========================================================================= 17 */ 18 #include <bits/stdc++.h> 19 using namespace std; 20 #define ll long long 21 #define max3(a,b,c) fmax(a,fmax(b,c)) 22 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0); 23 const double eps = 1e-6; 24 const int INF = 0x3f3f3f3f; 25 26 int a[1050],b[1050]; 27 int d[1050][1050]; 28 29 int main() 30 { 31 ios 32 #ifdef ONLINE_JUDGE 33 #else 34 freopen("in.txt","r",stdin); 35 // freopen("out.txt","w",stdout); 36 #endif 37 int T,N,V; 38 cin >> T; 39 while(T--) 40 { 41 cin >> N >> V; 42 for(int i = 1;i <= N;i++) 43 { 44 cin >> a[i]; 45 } 46 for(int i = 1;i <= N;i++) 47 { 48 cin >> b[i]; 49 } 50 memset(d,0,sizeof d); 51 for(int i = 1;i <= N;i++) 52 { 53 for(int j = 0;j <= V;j++) 54 { 55 if(j >= b[i]) 56 d[i][j] = max(d[i-1][j],d[i-1][j-b[i]]+a[i]); 57 else 58 d[i][j] = d[i-1][j]; 59 } 60 } 61 /* 優化空間複雜度 62 * int dp[1010]; 63 * memset(dp,0,sizeof dp); 64 * for(int i = 1;i <= N;i++) 65 * { 66 * for(int j = V;j >= b[i];j--) 67 * { 68 * dp[j] = max(dp[j],dp[j-b[i]]+a[i]); 69 * } 70 * } 71 */ 72 cout << d[N][V] << endl; 73 } 74 75 76 fclose(stdin); 77 // fclose(stdout); 78 return 0; 79 }
View Code

飯卡

描述

傳送門:飯卡

電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買一個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額為負),否則無法購買(即使金額足夠)。所以大家都希望儘量使卡上的餘額最少。
某天,食堂中有n種菜出售,每種菜可購買一次。已知每種菜的價格以及卡上的餘額,問最少可使卡上的餘額為多少。

輸入

多組資料。對於每組資料:
第一行為正整數n,表示菜的數量。n<=1000。
第二行包括n個正整數,表示每種菜的價格。價格不超過50。
第三行包括一個正整數m,表示卡上的餘額。m<=1000。

n=0表示資料結束。

輸出

對於每組輸入,輸出一行,包含一個整數,表示卡上可能的最小余額。

樣例

輸入

1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0

輸出

-45
32

思路

  • 首先將所有的菜排序
  • 求出還剩最後5元錢的時候能花掉的最多的金錢
  • 用最後的5元錢來買最貴的菜
  • 飯卡本來的金錢-能花掉最多的金錢-最貴的菜的價錢=要求的結果

程式碼

 1 /*
 2  * =========================================================================
 3  *
 4  *       Filename:  2546.cpp
 5  *
 6  *           Link:  http://acm.hdu.edu.cn/showproblem.php?pid=2546
 7  *
 8  *        Version:  1.0
 9  *        Created:  2018/07/12 11時40分47秒
10  *       Revision:  none
11  *       Compiler:  g++
12  *
13  *         Author:  杜寧元 (https://duny31030.github.io/), [email protected]
14  *   Organization:  QLU_浪在ACM
15  *
16  * =========================================================================
17  */
18 #include <bits/stdc++.h>
19 using namespace std;
20 #define ll long long
21 #define max3(a,b,c) fmax(a,fmax(b,c))
22 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
23 const double eps = 1e-6;
24 const int INF = 0x3f3f3f3f;
25 
26 int main()
27 {
28     ios
29 #ifdef ONLINE_JUDGE 
30 #else 
31         freopen("in.txt","r",stdin);
32     // freopen("out.txt","w",stdout); 
33 #endif
34     int n,m;
35     while(cin >> n && n != 0)
36     {
37         int a[1020];
38         int dp[1020];
39         memset(a,0,sizeof a);
40         int p;
41         p = n;
42         for(int i = 1;i <= n;i++)
43             cin >> a[i];
44         cin >> m;
45         if(m < 5)
46         {
47             cout << m << endl;
48         }
49         else 
50         {
51             memset(dp,0,sizeof dp);
52             sort(a+1,a+n+1);
53             for(int i = 1;i < n;i++)
54             {
55                 for(int j = m-5;j >= a[i];j--)
56                     dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
57             }
58         cout << m-dp[m-5]-a[n] << endl;
59         }
60     }
61 
62     fclose(stdin);
63     // fclose(stdout);
64     return 0;
65 }
View Code

Robberies

描述

傳送門:Robberies

The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before retiring to a comfortable job at a university.

For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible.

His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.

輸入

The first line of input gives T, the number of cases. For each scenario, the first line of input gives a floating point number P, the probability Roy needs to be below, and an integer N, the number of banks he has plans for. Then follow N lines, where line j gives an integer Mj and a floating point number Pj . Bank j contains Mj millions, and the probability of getting caught from robbing it is Pj .

輸出

For each test case, output a line with the maximum number of millions he can expect to get while the probability of getting caught is less than the limit set.

Notes and Constraints
0 < T <= 100
0.0 <= P <= 1.0
0 < N <= 100
0 < Mj <= 100
0.0 <= Pj <= 1.0
A bank goes bankrupt if it is robbed, and you may assume that all probabilities are independent as the police have very low funds.

樣例

輸入

3
0.04 3
1 0.02
2 0.03
3 0.05
0.06 3
2 0.03
2 0.03
3 0.05
0.10 3
1 0.03
2 0.02
3 0.05

輸出

2

4

6

思路

  • 要求出讓他不被抓情況下能搶的最多的金錢
  • 現在將他被抓的概率變為不被抓的概率,這樣只需要相乘便是他安全的概率
  • 只需要這個概率小於(1-p) 他便是安全的
  • 現在將他能搶到的金錢作為第二維、銀行數目作為第一維
  • 最後只需要倒序遍歷一遍求出第一個安全的位置,那麼這個位置的第二維便是他能搶劫的最多的金錢

程式碼

 1 /*
 2  * =========================================================================
 3  *
 4  *       Filename:  2955.cpp
 5  *
 6  *           Link:  http://acm.hdu.edu.cn/showproblem.php?pid=2955
 7  *
 8  *        Version:  1.0
 9  *        Created:  2018/07/15 14時30分24秒
10  *       Revision:  none
11  *       Compiler:  g++
12  *
13  *         Author:  杜寧元 (https://duny31030.github.io/), [email protected]
14  *   Organization:  QLU_浪在ACM
15  *
16  * =========================================================================
17  */
18 #include <bits/stdc++.h>
19 using namespace std;
20 #define ll long long
21 #define max3(a,b,c) fmax(a,fmax(b,c))
22 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
23 const double eps = 1e-9;
24 const int INF = 0x3f3f3f3f;
25 
26 int m[120];
27 double p[120];
28 double dp[10020];
29 
30 int main()
31 {
32     ios
33 #ifdef ONLINE_JUDGE 
34 #else 
35         freopen("in.txt","r",stdin);
36     // freopen("out.txt","w",stdout); 
37 #endif
38     int T,N;
39     double P;
40     cin >> T;
41     while(T--)
42     {
43         memset(dp,0,sizeof dp);
44         dp[0] = 1;
45         int sum = 0;
46         cin >> P >> N;
47         P = 1-P;
48         for(int i = 1;i <= N;i++)
49         {
50             cin >> m[i] >> p[i];
51             p[i] = 1-p[i];
52             sum += m[i];
53         }
54         
55         for(int i = 1;i <= N;i++)
56         {
57             for(int j = sum;j >= m[i];j--)
58             {
59                 dp[j] = max(dp[j],dp[j-m[i]]*p[i]);
60             }
61         }
62         for(int i = sum;i >= 0;i--)
63         {
64             if(P-dp[i] < eps)
65             {
66                 cout << i << endl;
67                 break;
68             }
69         }
70     }
71 
72     fclose(stdin);
73     // fclose(stdout);
74     return 0;
75 }
View Code

I NEED A OFFER!

描述

傳送門:I NEED A OFFER!

Speakless很早就想出國,現在他已經考完了所有需要的考試,準備了所有要準備的材料,於是,便需要去申請學校了。要申請國外的任何大學,你都要交納一定的申請費用,這可是很驚人的。Speakless沒有多少錢,總共只攢了n萬美元。他將在m個學校中選擇若干的(當然要在他的經濟承受範圍內)。每個學校都有不同的申請費用a(萬美元),並且Speakless估計了他得到這個學校offer的可能性b。不同學校之間是否得到offer不會互相影響。“I NEED A OFFER”,他大叫一聲。幫幫這個可憐的人吧,幫助他計算一下,他可以收到至少一份offer的最大概率。(如果Speakless選擇了多個學校,得到任意一個學校的offer都可以)。

輸入

輸入有若干組資料,每組資料的第一行有兩個正整數n,m(0<=n<=10000,0<=m<=10000)
後面的m行,每行都有兩個資料ai(整型),bi(實型)分別表示第i個學校的申請費用和可能拿到offer的概率。
輸入的最後有兩個0。

輸出

每組資料都對應一個輸出,表示Speakless可能得到至少一份offer的最大概率。用百分數表示,精確到小數點後一位。

樣例

輸入

10 3
4 0.1
4 0.2
5 0.3
0 0

輸出

44.0%

Note

You should use printf(“%%”) to print a ‘%’.

思路

  • 與上題類似

程式碼

 1 /*
 2  * =========================================================================
 3  *
 4  *       Filename:  1203.cpp
 5  *
 6  *           Link:  http://acm.hdu.edu.cn/showproblem.php?pid=1203
 7  *
 8  *        Version:  1.0
 9  *        Created:  2018/07/15 15時16分12秒
10  *       Revision:  none
11  *       Compiler:  g++
12  *
13  *         Author:  杜寧元 (https://duny31030.github.io/), [email protected]
14  *   Organization:  QLU_浪在ACM
15  *
16  * =========================================================================
17  */
18 #include <bits/stdc++.h>
19 using namespace std;
20 #define ll long long
21 #define max3(a,b,c) fmax(a,fmax(b,c))
22 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
23 const double eps = 1e-6;
24 const int INF = 0x3f3f3f3f;
25 double dp[10020];
26 int main()
27 {
28     ios
29 #ifdef ONLINE_JUDGE 
30 #else 
31         freopen("in.txt","r",stdin);
32     // freopen("out.txt","w",stdout); 
33 #endif
34     int n,m;
35     int a[10020];
36     double b[10020];
37     while(cin >> n >> m)
38     {
39         if(n == 0 && m == 0)
40             break;
41         memset(a,0,sizeof a);   memset(b,0,sizeof b);   // aemset(dp,0,sizeof dp); 
42         for(int i = 0;i < 10020;i++)
43             dp[i] = 1.0;
44         for(int i = 1;i <= m;i++)
45         {
46             cin >> a[i] >> b[i];
47             b[i] = 1-b[i];
48         }
49 
50         for(int i = 1;i <= m;i++)
51         {
52             for(int j = n;j >= a[i];j--)
53             {
54                 dp[j] = min(dp[j],dp[j-a[i]]*b[i]);
55             }
56         }
57         //double pr = 1.0;
58         //for(int i = 1;i <= n;i++)
59         //    pr = min(pr,dp[i]);
60         //pr = 1-pr;
61         //pr *= 100;
62         printf("%.1lf%%\n",(1-dp[n])*100);
63 
64     }
65 
66     fclose(stdin);
67     // fclose(stdout);
68     return 0;
69 }

Big Event in HDU

描述

傳送門:Big Event in HDU

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<N<1000) kinds of facilities (different value, different kinds).

輸入

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<V<=50 —value of facility) and an integer M (0<M<=100 —corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.

輸出

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.

樣例

輸入

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

輸出

20 10
40 40

思路

  • 需要讓分成的兩部分儘可能相等或者前者稍大於後者
  • 在輸入的時候計算所有價值總和 ②
  • 然後求出能夠取得的最接近一半價值總和的價值 ①
  • 如果②=2*① 則恰好可以被分為兩個相等的部分
  • ②-①為較多的那一部分

程式碼

 1 /*
 2  * =========================================================================
 3  *
 4  *       Filename:  1171.cpp
 5  *
 6  *           Link:  http://acm.hdu.edu.cn/showproblem.php?pid=1171
 7  *
 8  *        Version:  1.0
 9  *        Created:  2018/07/15 16時52分43秒
10  *       Revision:  none
11  *       Compiler:  g++
12  *
13  *         Author:  杜寧元 (https://duny31030.github.io/), [email protected]
14  *   Organization:  QLU_浪在ACM
15  *
16  * =========================================================================
17  */
18 #include <bits/stdc++.h>
19 using namespace std;
20 #define ll long long
21 #define max3(a,b,c) fmax(a,fmax(b,c))
22 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
23 const double eps = 1e-6;
24 const int INF = 0x3f3f3f3f;
25 
26 vector<int> a;
27 int dp[200020];
28 int main()
29 {
30     ios
31 #ifdef ONLINE_JUDGE 
32 #else 
33         freopen("in.txt","r",stdin);
34     // freopen("out.txt","w",stdout); 
35 #endif
36     int n,t1,t2,sum,sum2;
37     while(cin >> n)
38     {
39         if(n < 0)
40             break;
41         a.clear();
42         sum = 0;
43         memset(dp,0,sizeof dp);
44         for(int i = 1;i <= n;i++)
45         {
46             cin >> t1 >> t2;
47             sum += t1*t2;
48             while(t2--)
49                 a.push_back(t1);
50         }
51         sum2 = sum/2;
52         for(int i = 0;i < a.size();i++)
53         {
54             for(int j = sum2;j >= a[i];j--)
55                 dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
56         }
57         // printf("%d %d\n",max(dp[sum2],sum-dp[sum2]),min(dp[sum2],sum-dp[sum2]));
58         if(sum == dp[sum2]*2)
59             printf("%d %d\n",sum/2,sum/2);
60         else 
61             printf("%d %d\n",sum-dp[sum2],dp[sum2]);
62     }
63 
64 
65     fclose(stdin);
66     // fclose(stdout);
67     return 0;
68 }