【手把手刷CCF】201809-2-买菜100分(含详细注释)

本文介绍了如何使用C++实现一个算法,通过双层循环遍历两个时间段数组,计算它们的交叉时间。作者提供了详细的思路分析、代码实现以及剪枝优化,并给出了不使用剪枝的代码版本,展示了两者在效率上的微小差异。博客内容包括算法思路、代码展示、运行结果和题目背景。

前言

✨你好啊,我是“ 怪& ”,是一名在校大学生哦。
🌍主页链接:怪&的个人博客主页
☀️博文主更方向为:课程学习知识、作业题解、期末备考。随着专业的深入会越来越广哦…一起期待。
❤️一个“不想让我曾没有做好的也成为你的遗憾”的博主。
💪很高兴与你相遇,一起加油!

一、🌳🌳🌳思路如下

//代码中有写了许多注释哦

📢1、存储:

没有用结构体,直接用的数组,h[i]-h[i+1]是小H第i个时间段的装车时间,w[j]-w[j+1]是小W第i个时间段的装车时间。
请添加图片描述

📣2、算法思路

主体:两个for循环;外层是对小H的每个时间段,内层是对小W的每个时间段。

计算的情况共三种:
(1)、if(w[j]>h[i+1]){//w[j]开始时间>h[i+1]结束时间

即此时小W的第j个开始时间>小H第i个结束时间,对于W的时间继续循环增长与小H的此段肯定不会有交集的(恒大)。果断break;
请添加图片描述
(2)、else if(w[j+1]<h[i]){//w[j+1]结束时间<h[i]开始时间
即此时小W的第j个结束时间>小H第i个开始时间,W结束太早了,所以需要继续增长,跳到下一个时间段continue;
请添加图片描述
剪枝:在continue;前有flag=j+2;用于剪枝,因为如果每次都从j=0开始的话,许多数据都需要continue,所以用flag来记录小W的第flag个时间段刚好可以与小H的对应时间段有交叉。
(其实不剪枝也可以100分,两者的提交结果在“三、🔥🔥🔥提交结果”给出)。

(3)、除去(1)(2)两种情况剩下就是有交叉的啦,直接计算即可。
两个段的交叉如何计算?当然是用两者较小的结束时间减去两者较大的开始时间,即得两者的公共部分。可以再看图带入这个计算过程。
请添加图片描述
一句代码搞定:MeetTime=MeetTime+min(h[i+1],w[j+1])-max(h[i],w[j]);

二、🌟🌟🌟代码如下:

// 201809-2 买菜

#include <iostream>

using namespace std;
#define N 4002
int n;//n个时间段 
int h[N];//存h的时间段 
int w[N];//存w的时间段 
long long MeetTime;//记录见面时间 

int max(int m,int n){//自写取较大值的函数 
	if(m>n) return m;
	else return n;
}

int min(int m,int n){//自写取较小值的函数 
	if(m<n) return m;
	else return n;
}

void input(){//输入 
	cin>>n;
	for(int i=1;i<2*n;i=i+2){//输入h 
		cin>>h[i]>>h[i+1];
	} 
	for(int i=1;i<2*n;i=i+2){//输入w 
		cin>>w[i]>>w[i+1];
	}
} 

void output(){//输出 
	for(int i=1;i<2*n;i=i+2){//输入h 
		cout<<h[i]<<" "<< h[i+1]<<endl;
	}cout<<endl;
	 
	for(int i=1;i<2*n;i=i+2){//输入n 
		cout<<w[i]<<" "<<w[i+1]<<endl;
	}cout<<endl;
} 

void sum(){//计算 
	int flag=1;
	for(int i=1;i<2*n;i=i+2){
		for(int j=1;j<2*n;j=j+2){
			if(w[j]>h[i+1]){//w[j]开始时间>h[i+1]结束时间 
				break;//中断 
			}
			else if(w[j+1]<h[i]){//w[j+1]结束时间<h[i]开始时间 
				flag=j+2;
				continue;
			}
			else{//用两者结束时间较小值-两者开始时间较大值(即两者此时间段的交叉时间) 
				MeetTime=MeetTime+min(h[i+1],w[j+1])-max(h[i],w[j]);
			}
		}
	}
	cout<<MeetTime<<endl; 
}

int main(){
	input();
	//output(); //检验自己输入是否正确 
	sum();
	return 0;
} 

三、🔥🔥🔥提交结果:

请添加图片描述
不剪枝的sum()函数代码,其余皆一致:

void sum(){//计算 
	for(int i=1;i<2*n;i=i+2){
		for(int j=1;j<2*n;j=j+2){
			if(w[j]>h[i+1]){//w[j]开始时间>h[i+1]结束时间 
				break;//中断 
			}
			else if(w[j+1]<h[i]){//w[j+1]结束时间<h[i]开始时间 
				continue;
			}
			else{//用两者结束时间较小值-两者开始时间较大值(即两者此时间段的交叉时间) 
				MeetTime=MeetTime+min(h[i+1],w[j+1])-max(h[i],w[j]);
			}
		}
	}
	cout<<MeetTime<<endl; 
}

其提交结果:
请添加图片描述

emm……两者的时间使用是一样的,只不过节省了点空间。(👻平时当然要养成好习惯啦👻)

四、🌞🌞🌞题目如下:

请添加图片描述

❤️❤️❤️忙碌的敲代码也不要忘了浪漫鸭!

一起加油哦!💕💕💕

请添加图片描述

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怪&

感谢您的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值