《训练指南》——6.13
困于时间缘故和考试缠身,笔者在先前关于《训练指南》的而第二章的数学基础的介绍先告一段落,开始对第一章简单的一些算法基础题目进行介绍。
Uva11292:
你的王国里有一条n个头的恶龙,你希望雇一些其实把它杀死(即砍掉所有的头)。村里有m个其实可以雇佣,一个能力值为x的其实可以砍掉恶龙一个半径不超过x的头,且需要支付x个金币。如何雇佣其实才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个其实只能看一个头(且只能被雇用一次)。
分析:观察到题目给出支付最少的字眼,我们容易将其往动态规划或者贪心的算法思想上靠拢,而如果有一定动态规划基础的读者,可能会和笔者一样,认为它非常近似01背包的模型。
那么我们继续对比一下两个模型参量的区别看是否能够建立起联系,对于我们熟悉的01背包模型,即有n个价值、体积已知的物体,装入一个容积为v的背包,我们能够找到使得价值之和最大的方案,其主要的特征就是有n个物体,每个物体两个维度的参量(价值、体积),然后给出一个参量的限制(背包的体积,进一步抽象这个参量,可将其理解为费用),求解另一个参量的最值。
那么我们反过来看这道题目,m个人,有两个维度的参量:费用和能力。而对于n头龙,显然明显与01背包中容积为v的背包有着本质的区别,它会限制对勇士的选取,即不像01背包当中任何一个物体都可以放入背包,因此这里如果用01背包处理,仿佛并不是那么容易。
其实上面这个过程刻意将这个问题的思考复杂化了,其实这道问题很简单,它其实就基于一种最简单的贪心策略,然后会用到分而治之当中所谓“表示变更”(《算法谜题》当中有过介绍),我们只需要对m个勇士的能力进行从小到大排序,然后从能力较小者依次往后选取能够砍掉一个头的勇士即可。
简单的参考代码如下:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 20005; int main() { int boss[maxn],fighter[maxn]; int n , m; while(scanf("%d %d",&n,&m) && (m || n)) { for(int i = 1;i <= n;i++) scanf("%d",&boss[i]); for(int i = 1;i <= m;i++) scanf("%d",&fighter[i]); sort(boss + 1 , boss + n + 1); sort(fighter + 1 , fighter + m + 1); int index = 1; int sum = 0; for(int i = 1;i <= m;i++) { for(int j = index;j <= n;j++) { if(fighter[i] >= boss[j]) { index++; sum += fighter[i]; break; } } if(index == n + 1) break; } if(index == n + 1) printf("%d\n",sum); else printf("Loowater is doomed!\n"); } }
Uva 11729:
你有n个部下,每个部下需要完成一项任务。第i个部下需要你花Bi分钟交代任务,然后他会立刻独立的、无间断地执行Ji分钟后完成任务。你需要选择交代任务的顺序,是的所有任务今早执行完毕。注意,不能同时给两个部下交代任务,但部下们可以同时执行他们各自的任务。那么请问对于每组数据,输出完成任务的最短时间。
分析:基于一个时间区段上去思考这个问题。每个人所占有的时间区段分成两部分,交代任务和做任务。由于题设的限制,交代任务的区段是不可能重合的,那么这里我们考虑贪心策略,显然是让做任务区段最长的先去做任务,我们整个过程表述成如下的伪代码:
定义cost_time[i]是完成i个任务所有的最少时间
for i 1 to num_of_person
cost_time[i] = max(cost_time[i-1] , cost_time[i-1] – Ji[i-1]+ J[i] + B[i])
简单的参考代码如下(思路很清晰但是就是A不了,测了多组数据也能过,想扔在这里吧):
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 1005; struct person { int B , J; }; bool cmp(person a , person b) { return a.J >= b.J; } int main() { struct person p[maxn]; int n; int tt = 1; while(scanf("%d",&n) && n != 0) { for(int i = 1;i <= n;i++) { scanf("%d%d",&p[i].B,&p[i].J); } sort(p + 1 , p + n + 1 , cmp); // printf("%d %d %d",p[1].J,p[2].J,p[3].J); int cost_time = p[1].B + p[1].J; for(int i = 2;i <= n;i++) { cost_time = max(cost_time , cost_time - p[i-1].J + p[i].J + p[i].B); // printf("%d ",cost_time); } printf("Case %d: %d\n",tt++,cost_time); } }