以“采药”为例谈剪枝

1746: 【NOIP05普及组】采药

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 如果你是辰辰,你能完成这个任务吗?

输入:
第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出:
一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

输入样例:

70 3
71 100
69 1
1 2

输出样例:

3

分析:M种药,每种药有各自的耗时和价值,要求在T时间内,采一些药使得总价值最大。

我们用01串表达采药的方案。以三种药为例:

111 表示 第1、2、3种药都采;

110表示 采第1、2种药第三种药不采;

……

3种药总共有8种方案:

000

001

010

011

100

101

110

111

我们可以在总耗时小于T的那些方案中,寻找价值和最大的方案。

首先我们来写一个代码产生表示方案的01串。

 1 # include <bits/stdc++.h>
 2 using namespace std;
 3 int n,a[101];
 4 void dfs(int dep){
 5    if(dep>n){
 6        for (int i=1;i<=n;i++) cout<<a[i];
 7        cout<<endl;
 8    }
 9    else{
10                 a[dep]=1;
11                 dfs(dep+1);
12                 a[dep]=0;
13                 dfs(dep+1);
14     }
15 }
16 
17 int main(){
18    cin>>n;
19    dfs(1);
20    return 0 ; 
21 
22     return 0;
23 }
View Code

改进一下代码:

 1 # include <bits/stdc++.h>
 2 using namespace std;
 3 int n,a[101];
 4 void dfs(int dep){
 5    if(dep>n){
 6        for (int i=1;i<=n;i++) cout<<a[i];
 7        cout<<endl;
 8    }
 9    else{
10         for(int i=0;i<=1;i++){
11               a[dep]=1-i;
12                 dfs(dep+1);
13             }
14     }
15 }
16 
17 int main(){
18    cin>>n;
19    dfs(1);
20    return 0 ; 
21 
22 }
View Code

方案形成后,打擂台记录最大价值

 1 //  http://www.jzoj.cn/problem.php?id=1746  
 2 // 20%
 3  
 4 # include <bits/stdc++.h>
 5 using namespace std;
 6 int n,a[101];
 7 int W,w[101],v[101],maxv;
 8 
 9 void dfs(int dep){
10    if(dep>n) //方案处理,计算这个方案的总重量和总价值 
11    {
12            int tw=0,tv=0; 
13            for (int i=1;i<=n;i++) {
14            tw+=a[i]*w[i];
15               tv+=a[i]*v[i];
16           }
17         if(tw<=W && tv>maxv) {
18             maxv=tv;
19         }
20    } 
21    else{
22         for(int i=0;i<=1;i++){
23               a[dep]=1-i;
24                 dfs(dep+1);
25             }
26 
27     }
28 }
29 
30 int main(){
31    cin>>W>>n;
32    for(int i=1; i<=n; i++)  cin>>w[i]>>v[i];
33    dfs(1);
34    cout<<maxv<<endl; 
35    return 0 ; 
36 
37 }
View Code

改进代码,我们在方案产生时,记录总耗时和总价值:

 1 //  http://www.jzoj.cn/problem.php?id=1746  
 2 // 25%
 3 
 4 # include <bits/stdc++.h>
 5 using namespace std;
 6 int n,a[101];
 7 int W,w[101],v[101],maxv;
 8 int tw,tv;
 9 
10 void dfs(int dep){
11    if(dep>n) //方案处理,计算这个方案的总重量和总价值 
12    {
13       if(tv>maxv) maxv=tv;    
14    } 
15    else{
16         for(int i=0;i<=1;i++){
17               a[dep]=1-i;
18               if(tw+a[dep]*w[dep]<=W){
19                   tw+=a[dep]*w[dep];
20                 tv+=a[dep]*v[dep];
21                 dfs(dep+1);
22                 tw-=a[dep]*w[dep];
23                 tv-=a[dep]*v[dep];
24               }
25             }
26 
27     }
28 }
29 
30 int main(){
31    cin>>W>>n;
32    for(int i=1;i<=n;i++)  cin>>w[i]>>v[i];   
33    dfs(1);
34    cout<<maxv<<endl; 
35    return 0 ; 
36 
37 }
View Code

有些方案还没形成时我们就知道不可能有更优解了,来一次剪枝:

 1 //  http://www.jzoj.cn/problem.php?id=1746  
 2 // 30%
 3 # include <bits/stdc++.h>
 4 using namespace std;
 5 int n,a[101];
 6 int W,w[101],v[101],maxv;
 7 int tw,tv;
 8 
 9 int rest(int dep) //记录剩余药草的总价值 
10 {
11     int s=0;
12     for(int i=dep;i<=n;i++) s+=v[i];
13     return s;
14 }
15 
16 void dfs(int dep){
17    if(dep>n) //方案处理,计算这个方案的总重量和总价值 
18    {
19       if(tv>maxv) maxv=tv;    
20    } 
21    else{
22         for(int i=0;i<=1;i++){
23               a[dep]=1-i;
24               if(tw+a[dep]*w[dep]<=W && tv+a[dep]*v[dep]+rest(dep+1)>maxv  ){
25                   tw+=a[dep]*w[dep];
26                 tv+=a[dep]*v[dep];
27                 dfs(dep+1);
28                 tw-=a[dep]*w[dep];
29                 tv-=a[dep]*v[dep];
30               }
31             }
32 
33     }
34 }
35 
36 int main(){
37    cin>>W>>n;
38    for(int i=1;i<=n;i++)   cin>>w[i]>>v[i];
39    
40    dfs(1);
41    cout<<maxv<<endl; 
42    return 0 ; 
43 
44 
45 }
View Code

最后还是解决不了,M过大的问题,终结方法DP:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int t,m,w[105],v[105],f[105][1005];
 4 int main()
 5 {
 6   cin>>t>>m;
 7   for(int i=1; i<=m; i++)
 8     cin>>w[i]>>v[i];
 9   for(int i=1; i<=m; i++)
10   {
11     for(int j=t; j>=0; j--)
12     {
13       if(j>=w[i])
14         f[i][j]=max(f[i-1][j-w[i]]+v[i],f[i-1][j]);
15       else f[i][j]=f[i-1][j];
16     }
17   }
18   cout<<f[m][t];
19 }
View Code

 

posted @ 2023-07-21 09:49  flatten  阅读(21)  评论(0)    收藏  举报