一、硕鼠游戏
1.题目
小老鼠准备了 M 磅的猫粮,准备去和看守仓库的猫做交易,因为仓库里有小老鼠喜欢吃的五香豆。
仓库有 N 个房间;
第 i 个房间有 J[i] 磅的五香豆,并且需要用 F[i] 磅的猫粮去交换;
老鼠不必交换该房间所有的五香豆,换句话说,它可以用 F[i]∗a% 磅的猫粮去换取 J[i]∗a% 磅的五香豆,其中 a 是一个实数。
现在,请帮忙计算一下,小老鼠最多能够得到多少磅的五香豆?
++要求++:
输入包含多组测试用例。
每组测试数据首先一行是 2 个非负整数 M 和 N ,接着的 N 行,每行分别包含 2 个非负整数 J[i] 和 F[i] 。
输入数据以两个 −1 结束。
题目保证所有的数据不超过 1000
请计算并输出小老鼠最多能够得到的五香豆数量。
每组数据输出一行,保留 3 位小数。
2.题解
这是一个典型的贪心算法题
即不考虑全局,优先考虑局部最优解(全局是否最优需要证明)
代入题目即寻找能够获得最多猫粮的方案
有了思路,接下来便到了写代码的时候
读完要求我们会发现,每组数据有N个房间,每个房间至少包含两个数据(五香豆和猫粮),很明显,房间可以用一个结构体数组来表示,而数据则可以纳入对应结构体
结构体代码如下
cs
struct mou{
int beans;//存储房间内的豆子数量
int mon;//存储需要缴纳的猫粮
double mid;//计算单位数量的猫粮可兑换的豆子数量
};
核心算法如下
cs
while(M){
if(i<0){
break;
}
if(M>=moulist[i].mon){
sum+=moulist[i].beans;
M-=moulist[i].mon;
}else{
sum+=moulist[i].mid*M;
M=0;
}
i--;
}
注:计算前先将结构体数组(moulist)按照mid大小排序
3.完整代码
cs
#include<stdio.h>
#include<stdlib.h>
struct mou{
int beans;
int mon;
double mid;
};
int compare(const void *a,const void *b){
struct mou *m1 = (struct mou*)a;
struct mou *m2 = (struct mou*)b;
if(m1->mid > m2->mid) return 1;
if(m1->mid < m2->mid) return -1;
return 0;
}
int main(){
int M,N;
while(1){
scanf("%d %d",&M,&N);
if(M==-1&&N==-1){
break;
}
struct mou *moulist=(struct mou*)malloc(sizeof(struct mou)*N);
for(int i=0;i<N;i++){
struct mou m;
scanf("%d %d",&m.beans,&m.mon);
m.mid=(double)m.beans/m.mon;
moulist[i]=m;
}
qsort(moulist,N,sizeof(struct mou),compare);
double sum=0;
int i=N-1;
while(M){
if(i<0){
break;
}
if(M>=moulist[i].mon){
sum+=moulist[i].beans;
M-=moulist[i].mon;
}else{
sum+=moulist[i].mid*M;
M=0;
}
i--;
}
printf("%.3lf\n", sum);
free(moulist);
}
return 0;
}
二、田忌赛马
1.题目
"田忌赛马" 是中国历史上一个著名的故事。
大约2300年前,齐国大将田忌喜欢和国王赛马,并且约定:每赢一场,对方就要付 200 元。
假设已知田忌和国王的各自马匹的速度都不相同,请计算田忌最好的结果是什么。
++要求++:输入包含多组测试样例。
每组样例的第一行是一个整数 n(n<=1000),表示田忌和国王各自参赛的马匹数量。
接下来一行的 n 个整数表示田忌的马的速度,再接下来一行的 n个整数表示国王的马的速度。
n 为 0 时,表示输入数据的结束。
每组数据输出一行,表示田忌最多能够赢得的金额。
2.题解
这道题有两种情况:一种是田忌的马比国王的好,此时直接比就行;另一种是田忌的马比国王的差,此时则需要贪心算法
我们可以定义两个数组(t(田忌)和g(国王))用于存储马的质量
然后将二者分别排序便于后续操作
cs
int compare(const void *a,const void *b){
return (*(int*)a-*(int*)b);
}
int main(){
int t[n+1];
int g[n+1];
for(int i=0;i<n;i++){
scanf("%d",&t[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&g[i]);
}
qsort(t,n,sizeof(int),compare);
qsort(g,n,sizeof(int),compare);
}
核心算法如下
cs
int l=0;
int r=n-1;
int sum=0;
for(int i=n-1;i>=0;i--){
if(g[i]<t[r]){
r--;
sum++;
}else if(g[i]>t[r]){
l++;
sum--;
}
}
3.完整代码
cs
#include<stdio.h>
#include<stdlib.h>
int compare(const void *a,const void *b){
return (*(int*)a-*(int*)b);
}
int main(){
int n;
while(1){
scanf("%d",&n);
if(n==0){
break;
}
int t[n+1];
int g[n+1];
for(int i=0;i<n;i++){
scanf("%d",&t[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&g[i]);
}
qsort(t,n,sizeof(int),compare);
qsort(g,n,sizeof(int),compare);
int l=0;
int r=n-1;
int sum=0;
for(int i=n-1;i>=0;i--){
if(g[i]<t[r]){
r--;
sum++;
}else if(g[i]>t[r]){
l++;
sum--;
}
}
printf("%d\n",sum*200);
}
return 0;
}
三、搬桌子
1.题目
已知楼层房间情况如下:

楼层中间是走廊,两侧各有 200 个房间,编号如图。
由于内部调整,需要把一些桌子从一个房间搬到另外的房间。
因为走廊很窄,但是桌子很大,所以同一段走廊每次只能通过一个桌子。
假设不论远近,每趟搬桌子都需要 10 分钟。
同时,当你从 房间i 搬桌子到 房间j 的过程中,房间i 到 房间j 之间的走廊都被占用,也就是说,在每个10分钟内,不能有多个任务共享同一段走廊。
现在,要完成所有的搬运任务,最少需要多少时间?
++要求:++ 输入包含 T 组测试用例。
每组测试用例首先是一个正整数 N(1<=N<=200),表示需要搬运的桌子数量。
接下来 N 行,每行包含 2 个正整数 s 和 t,表示需要将一个桌子从 房间s 搬到 房间t。
计算并输出完成所有的搬运任务需要的最少的时间,每组数据占一行。
2.题解
由题可知,中间一段走廊可以分为200段
那么如何找出总搬运时间呢?
其实很简单,我们只需用一个大小为201的数组来表示走廊,并初始化为0,然后每搬运一次就让其加一,最后找出最大重叠数乘10即可
(注意避开活动选择思想误区:即优先选择最早结束且满足要求的区间)
3.完整代码
cs
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int T;
scanf("%d",&T);
for(int i=0;i<T;i++){
int N;
scanf("%d",&N);
int corridor[201] = {0}; // 走廊段,索引1-200
for(int j=0;j<N;j++){
int s, t;
scanf("%d %d",&s,&t);
// 确保s <= t
if(s > t){
int temp = s;
s = t;
t = temp;
}
// 将房间号映射到走廊段
// 房间1-2 → 走廊段1,房间3-4 → 走廊段2,以此类推
int start = (s + 1) / 2;
int end = (t + 1) / 2;
// 标记被占用的走廊段
for(int k=start; k<=end; k++){
corridor[k]++;
}
}
// 找出最大重叠数
int max_overlap = 0;
for(int j=1; j<=200; j++){
if(corridor[j] > max_overlap){
max_overlap = corridor[j];
}
}
printf("%d\n", max_overlap * 10);
}
return 0;
}
4.错误写法(活动选择思想)
这里再贴一下主包一开始的错误写法(还超时了)
(这并不贪心,而是另一种并排的思想)
cs
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
struct Rom{
int s,t;
int num;
};
int compare(const void *a,const void *b){
struct Rom *m1 = (struct Rom*)a;
struct Rom *m2 = (struct Rom*)b;
if(m1->t > m2->t) return 1;
if(m1->t < m2->t) return -1;
return 0;
}
int main(){
int T;
scanf("%d",&T);
for(int i=0;i<T;i++){
int N;
scanf("%d",&N);
struct Rom *romlist=(struct Rom*)malloc(sizeof(struct Rom)*N);
for(int j=0;j<N;j++){
struct Rom ro;
scanf("%d %d",&ro.s,&ro.t);
ro.num=1;
romlist[j]=ro;
}
qsort(romlist,N,sizeof(struct Rom),compare);
int a=N;
int sum=0;
int min=romlist[0].t;
while(a){
for(int j=0;j<N;j++){
if(romlist[j].s>=min&&romlist[j].num!=0){
sum++;
romlist[j].num=0;
a--;
min=romlist[j].t;
}
}
}
printf("%d",sum*10);
}
return 0;
}
当笔记写了/doge
四、活动选择
1.题目
"今年暑假不AC?"
"是的。"
"那你干什么呢?"
"看世界杯呀,笨蛋!"
"@#$%^&*%..."
确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
**++要求++:**输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Tis,Tie (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
2.题解
这是典型的活动选择题目
先定义节目结构体
cs
struct Rom{
int s,t;
};
然后定义节目结构体数组
cs
struct Rom *romlist=(struct Rom*)malloc(sizeof(struct Rom)*N);
并将其按照结束时间排序
cs
qsort(romlist,N,sizeof(struct Rom),compare);
贪心算法
cs
int count = 1; // 至少可以选择第一个活动
int last_end = romlist[0].t;
for(int j=1;j<N;j++){
if(romlist[j].s >= last_end){
count++;
last_end = romlist[j].t;
}
}
最后释放内存
3.完整代码
cs
#include<stdio.h>
#include<stdlib.h>
struct Rom{
int s,t;
};
int compare(const void *a,const void *b){
struct Rom *m1 = (struct Rom*)a;
struct Rom *m2 = (struct Rom*)b;
if(m1->t > m2->t) return 1;
if(m1->t < m2->t) return -1;
return 0;
}
int main(){
int N;
while(1){
scanf("%d",&N);
if(N==0){
break;
}
struct Rom *romlist=(struct Rom*)malloc(sizeof(struct Rom)*N);
for(int j=0;j<N;j++){
scanf("%d %d",&romlist[j].s,&romlist[j].t);
}
qsort(romlist,N,sizeof(struct Rom),compare);
int count = 1;
int last_end = romlist[0].t;
for(int j=1;j<N;j++){
if(romlist[j].s >= last_end){
count++;
last_end = romlist[j].t;
}
}
printf("%d\n",count);
free(romlist);
}
return 0;
}