两个采药(东方化改题+xjb注释的题解)

【问题描述】

辉夜是个天资聪颖的少女,她的梦想是成为世界上最伟大的医师。为此,她想拜附近

最有威望的医师永琳为师。永琳为了判断她的资质,给她出了一个难题。永琳把她带到一

个到处都是草药的山洞里对她说:“孩子,这个山洞里有一些不同的草药,采每一株都

需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可

以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辉夜,你能完成这个任务吗?

【输入文件】

输入文件medic.in的第一行有两个整数T和M,用一个空格隔开,T代表总共能够用来

采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个整数,分别表示

采摘某株草药的时间和这株草药的价值。

【输出文件】

输出文件medic.out包括一行,这一行只包含一个整数,表示在规定的时间内,可以采

到的草药的最大总价值。如果不能完成这个任务输出“不能”。

参考代码是:

1 #include<cstdio>
2 using namespace std;
3 int main()
4 {
5     printf("不能");
6     return 0;
7 }

啊,当然不是。                                                                                                                 

这个题有两种数据范围,分别对应两种代码

第一种:

1 <= T <= 1000

1 <= M <= 100

对于30%的数据,M <= 10;

对于全部的数据,M <= 100。

这个呢就是动态规划做01背包,非常简单

 1 #include<cstdio>
 2 using namespace std;
 3 int v,p,T,M,dp[1005];
 4 int main()
 5 {
 6     freopen ("medic.in","r",stdin); 
 7     freopen ("medic.out","w",stdout);
 8     scanf("%d%d",&T,&M);
 9     for (int i=1;i<=M;i++)
10     {
11         scanf("%d%d",&v,&p);
12         for (int j=T;j>=v;j--)
13             dp[j]=max(dp[j],dp[j-v]+p);    //递推式子,j是剩余时间 
14     }
15     printf("%d",dp[T]);
16     return 0;
17 }

总体来说背包的递推通式就是:

1 f[j] = max(f[j],f[j-v[i]]+w[i])

当然这是数据范围比较小的情况……

第二种:

50%的数据中 T,M ≤ 1000;

100%的数据中 T,M ≤ 100000,Ti,V≤10。

这个需要加上奇奇怪怪的优化

我不会

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <string>
 5 #include <stdlib.h>
 6 #include <vector>
 7 #include <algorithm>
 8 #include <math.h>
 9 using namespace std;
10 const int MAXN=100050;
11 int box[11][11],dp[MAXN],N,M,t1,t2,er[25],ge[20];  
12 void solve(int v,int p,int n);
13 void solve(int v,int p,int n)
14 {
15     int t=n,time=0,v1,p1;
16     memset(ge,0,sizeof(ge));
17     for (int i=1;i<=20;i++)
18     {
19         if (t-er[i]>=0) 
20         {
21             ge[i]=er[i];
22             t-=er[i];
23             time=i;
24         }
25         else
26         {
27             ge[i]=t;
28             time=i;
29             break;
30         }
31     }
32     for (int i=1;i<=time;i++)
33     {
34         v1=ge[i]*v;
35         p1=ge[i]*p;
36         for (int j=M;j>=v1;j--)
37             dp[j]=max(dp[j],dp[j-v1]+p1);    //递推式子 
38     }
39 }
40 int main()
41 {
42     freopen ("medic2.in","r",stdin); 
43     freopen ("medic2.out","w",stdout);
44     scanf("%d%d",&N,&M);
45     er[1]=1;
46     for (int i=2;i<=20;i++)
47         er[i]=er[i-1]<<1;
48     for (int i=1;i<=N;i++)
49     {
50         scanf("%d%d",&t1,&t2);
51         box[t1][t2]++;
52     }
53     
54     for (int i=1;i<=10;i++)
55     {
56         for (int j=1;j<=10;j++)
57             if (box[i][j])
58                 solve(i,j,box[i][j]);
59     }
60     printf("%d\n",dp[M]);
61 //    cout<<dp[M]<<endl;
62 //    solve(1,2,box[1][2]);
63     return 0;
64 } 

啊gg让我们写题解可是我不想写

转载于:https://www.cnblogs.com/aristocrat/p/8496123.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值