csp 23-03-1 田地丈量 & 2垦田计划

田地丈量

问题

给定一块区域。计算若干已有区域与改区域的交集

我的思路

很死板,而且没有抓住问题的关键。因为题目给的条件是左下和右上的坐标,我就顺着走了,只考虑了,这两个点,试图把所有情况都分析出来,使用if来判断,点是否在这个区域,然后根据不同的情况,来具体计算面积。但只判断了这两个点,实际上,从样例解释就能看出来,如果你要判断的话,四个点都要判断,情况很多,也很复杂。这个时候,要往根本去想,当时也有想到一点,在计算面积时也触及到思路,但是没能上升,戛然而止了。

优秀的思路

CSP202303-1 田地丈量
参考了博主的文章
问题简化一下,就是计算,矩形的面积,但是这个面积要在一定的范围,所以就是,求出每块田地在这个范围内的长和宽就好了。
坐标求长宽:宽 = 右x - 左x ;长 = 上y - 下y。
求交叉长宽:宽 = min(右x ,右边界)- max(左x,左边界);
长 = min(上y ,上边界)- max(下y,下边界);
带入本题的值就是如代码所示:

#include <iostream>
#include <vector>

using namespace std;
int a,b;

int main() {
	int n;
	cin >> n >> a >> b;
	int x1, y1, x2, y2;
	int x, y;
	int sum = 0;
	for(int i = 0; i < n; i++) {
		cin >> x1 >> y1 >> x2 >> y2;
		x = min(x2,a) - max(0,x1);
		y = min(y2,b) - max(0,y1);
		if(x >= 0 && y >= 0) {
			sum += x * y;
		}
	}
	cout << sum << endl;
	return 0;
}

get

遇到问题不要只想一层,如果思路有问题,可以试着从问题倒推,而且计算矩形面积,不是理所当然的一个长宽就可以吗,不要把问题弄得复杂,要能抓到关键点。

垦田计划

问题

多块地同时开垦,每块地的耗时可以通过投入资源来降低,要求求得最低时耗。

我的思路

根据基础时耗(降序),-1天需要的资源(升序),综合排序,每次都选择当前时耗最大的,-1消耗最小的,步长为①的分配资源试探。当时耗都相同之后,就可以计算整体的-1需要资源,看能往前走几步,然后就可以了。

满分思路

参考博主文章
CCF-CSP真题《202303-2 垦田计划》思路+python,c++满分题解
博主的思路是,使用一个map,将时耗天数相等的地合并起来,<时耗,-1需要的总资源数>,然后就可以从最大时耗开始多块地一天天的往前试探,减去后,与时耗相同的键值对合并,继续试探,呜呜呜呜效率真的好高。
在这里插入图片描述
这里是根据博主的思路和代码写的代码

#include<bits/stdc++.h>
using namespace std;

int main() {
	int n, m, k;
	map<int,int> time, res, flag;
	cin >> n >> m >> k;
	int max = 0;//记录最大时耗的天数
	for(int i = 0; i < n; i++) {
		cin >> time[i] >> res[i];
		max = max > time[i] ? max : time[i];
		flag[time[i]] += res[i];
		//将时耗相等的地合并起来,键为时耗,值为累积起来的,-1天所需要的资源
	}
	while(m > 0) {
		if(max == k)
			break;
		if(m >= flag[max]) {
			m -= flag[max]; //最大时耗的地全部减一天
			flag[max - 1] += flag[max]; 
			//最大时耗减一天,如果原先不存在max-1的时耗,map会自动创建,且初始值为0
			max-- ;//当前最大时耗减一
		} else break;
	}
	cout << max << endl;
	return 0;
}

我的思路实现了,虽然超时,但还是想记录一下,辛苦写的垃圾(允悲
在这里插入图片描述

#include <iostream>
#include <vector>

using namespace std;

int n;

int findT(vector<vector<int> > T) {
	// 遍历一遍找到 时耗最大的地的下标
	int maxT = T[0][0], minC = T[0][1];
	int t = 0;
	int num = 1; // 记录相等时耗的次数,用于判断是否已经达到时耗全都相等的时候
	for (int i = 1; i < n; i++) {
		if(T[i][0] >= maxT) {
			if(T[i][0] == maxT) {
				num++;
				if(T[i][1] < minC) {
					maxT = T[i][0];
					minC = T[i][1];
					t = i;
				}
			} else {
				maxT = T[i][0];
				minC = T[i][1];
				t = i;
			}
		}
	}
	if(num == n)
		return -1;
	return t;
}

int main() {
	int m, k;//总地数,总资源,最低时耗
	cin >> n >> m >> k;
	vector<vector<int> > T(n, vector<int>(2));
	for(int i = 0; i < n; i++) {
		cin >> T[i][0] >>T[i][1];
	}
	int index;
	while( m >= 0 ) {
		index = findT(T);
		if(index == -1) {
		// 时耗全都相等的时候的统一处理
			int sumC = 0;
			for(int i = 0; i < n; i++) {
				sumC += T[i][1];
			}
			if( m / sumC ) {
				if((T[0][0] - m/sumC) <= k)
					cout << k << endl;
				else cout << T[0][0] - m/sumC << endl;
			} else cout << T[0][0] << endl;
			return 0;
		}
		if( T[index][0] == k ) {
			cout << k << endl;
			return 0;
		}
		m -= T[index][1]; //减去一份资源
		if( m >= 0 )
			T[index][0]--; //时耗减一
		else break;
	}
	index = findT(T);
	cout << T[index][0] << endl;
	return 0;
}
get

做题不能死扣了,想到了思路就非要实现。想半小时,写半天,错了再改半天,晚上又优化半天,终于提交了,然后超时。
一开始的一块地一天的步长试探就不够,其实我已经发现,当时时耗相同时,可以同时考虑,反正最低时耗是取决与最大的,如果不能全都减一,那就是不能减一。只是没有从一开始就想到,把时耗相同的就放在一起考虑,降下去一天之后就可以,再与相同时耗的地合并,效率嘎嘎的。
发现map好神奇,之前没学会,原来没有的值,它还能自动创建。还是有序的,不过虽然有序但是键值对不是数组,还是要记录最大值的。

  • 37
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 农夫约翰想要丈量他的 N(1≤N≤100,000)个田地的面积。他有一条长为 L(1≤L≤1,000,000)的量尺,可以用来测量在一个平面上的距离。每个田地都是一个矩形,且所有矩形的边都平行于坐标轴。每个矩形的左下角和右上角的坐标分别为 (x1,y1) 和 (x2,y2),其中 0≤x1<x2≤L,0≤y1<y2≤L。你需要编写一个程序来计算所有田地的总面积。 输入格式: 第一行包含两个整数 N 和 L。 接下来 N 行,每行包含四个整数 x1,y1,x2,y2,表示一个矩形的左下角和右上角坐标。 输出格式: 输出所有田地的总面积。 样例输入: 3 10 0 0 1 1 1 1 5 5 5 5 10 10 样例输出: 100 解题思路: 首先,根据输入的坐标信息,我们可以计算出每个矩形的面积。这个很简单,只需要将矩形的宽和高相乘即可。 然后,我们需要判断每个矩形是否与其他矩形重叠。如果重叠了,我们就需要将重叠的部分减掉。这个问题也很简单,只需要找出所有相交的矩形,计算它们重叠的面积,然后将它们的面积减掉即可。 最后,将所有矩形的面积加起来,就是所有田地的总面积了。 具体实现时,我们可以使用一个二维数组来表示每个坐标上的矩形数量。然后,我们可以对每个矩形进行遍历,找出所有与它相交的矩形,并计算它们的重叠面积。最后,将所有矩形的面积加起来即可。 参考代码:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值