寒假作业第二组P&&Q&&R题解
P的题意是有M份作业,这些作业有不同的截止日期,超过截止日期完成,不同的作业有不同的罚分,求如何完成罚分最低。
首先,从截止日期最长的那个作业到截止日期,这些天数是固定的,所做的就是把这些作业填进这些天。很明显的贪心,把作业按从大到小罚分排序,罚分截止日期越近的放在前面,然后通过枚举把作业往时间轴里放,知道这些天数被填满。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <map> 5 #include <string> 6 #include <string.h> 7 #include <queue> 8 #include <vector> 9 using namespace std; 10 struct subject{ 11 int point; 12 int time; 13 }; 14 int compare(struct subject a,struct subject b) 15 { 16 if(a.point!=b.point) 17 { 18 if(a.point>b.point) 19 return 1; 20 else return 0; 21 } 22 else { 23 if(a.time<b.time) 24 return 1; 25 else return 0; 26 } 27 } 28 int main() 29 { 30 int n; 31 scanf("%d",&n); 32 for(int i=0;i<n;i++) 33 { 34 int m; 35 int sum=0; 36 int flag[1000]={0}; 37 struct subject sb[2000]; 38 int a[10000]={0}; 39 int b[10000]={0}; 40 scanf("%d",&m); 41 for(int j=0;j<m;j++) 42 { 43 scanf("%d",&a[j]); 44 sb[j].time=a[j]; 45 } 46 for(int h=0;h<m;h++) 47 { 48 scanf("%d",&b[h]); 49 sb[h].point=b[h]; 50 } 51 sort(sb,sb+m,compare); 52 for(int g=0;g<m;g++) 53 { 54 for(int j=sb[g].time;j>=0;j--) 55 { 56 if(!flag[j]&&j) 57 { 58 flag[j]=1; 59 break; 60 } 61 if(!j) 62 sum+=sb[g].point; 63 } 64 } 65 printf("%d\n",sum); 66 } 67 return 0; 68 }
Q的题意其实跟DOTA没啥关系,可以理解成回合制游戏,只不过每次都是敌人先攻击你,你的血量无限,不过你每次只能打对方一点血,对方有DFS(每次攻击你掉的血)和HP(血量)两个特征,求把他们打死,你消耗的最少血量。既然是贪心,就要排序,按DFS排还是按HP排呢,都不是,因为你优先要打的是,HP低&&攻击力强的敌人,所以应该优先打DFS/HP大的敌人。
#include <iostream> #include <algorithm> #include <cstdio> #include <map> #include <string> #include <string.h> #include <queue> #include <vector> using namespace std; struct hero{ int dps; int hp; }; int compare(struct hero a,struct hero b) { if((a.dps*1.0/a.hp)>(b.dps*1.0/b.hp)) return 1; else return 0; } int main() { int n; while(scanf("%d",&n)!=EOF) { int sum=0; struct hero a[1000]; for(int i=0;i<n;i++) scanf("%d%d",&a[i].dps,&a[i].hp); sort(a,a+n,compare); for(int j=0;j<n;j++) { for(int h=j;h<n;h++) { sum+=a[h].dps*(a[j].hp); } } printf("%d\n",sum); } return 0; }
R题,题意很简单,有n个机器,m个任务,每个机器和任务都对应着 time和level两个量,只有机器的时间和等级都大于等于任务时,才能完成任务,求完成任务的最大数量,多解考虑利润最多的情况,利润是任务的时间*500+等级*2;
因为任务的时间权重很高,所以可以直接忽略利润这个东西。
我本来的想法是,从最简单地任务开始(简单就是时间少且等级低,首要看时间)每个任务,都从最烂的机器(烂机器就是时间少,等级低)开始匹配,匹配上的机器用flag标记,结果超时了,确实,这么做太暴力,因为任务的简单和机器的烂是有联系的,特别是当他们被排好顺序的时候。最后借鉴了别人的方法。从最难的任务开始,然后先挑出一部分时间上满足的机器,然后再看等级。再下一个任务,因为排好序所以比上一个任务简单,可以继续用到上一次被挑出来的机器,还可以继续挑选机器,节省了时间。
#include <iostream> #include <algorithm> #include <cstdio> #include <map> #include <string> #include <string.h> #include <queue> #include <vector> using namespace std; struct com{ int time; int level; }; int compare(struct com a,struct com b) { if(a.time!=b.time) { if(a.time>b.time) return 1; else return 0; } else return a.level>b.level; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { struct com mac[100010]; struct com task[100010]; int flag[100010]={0}; int cnt=0; long long sum=0; for(int i=0;i<n;i++) scanf("%d%d",&mac[i].time,&mac[i].level); for(int j=0;j<m;j++) scanf("%d%d",&task[j].time,&task[j].level); sort(mac,mac+n,compare); sort(task,task+m,compare); for(int i=0,j=0;i<m;i++) { while(j<n&&mac[j].time>=task[i].time) { flag[mac[j].level]++; j++; } for(int h=task[i].level;h<=100;h++) { if(flag[h]) { flag[h]--; cnt++; sum+=500*task[i].time+2*task[i].level; break; } } } printf("%d %lld\n",cnt,sum); } return 0; }