田地丈量
问题
给定一块区域。计算若干已有区域与改区域的交集
我的思路
很死板,而且没有抓住问题的关键。因为题目给的条件是左下和右上的坐标,我就顺着走了,只考虑了,这两个点,试图把所有情况都分析出来,使用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好神奇,之前没学会,原来没有的值,它还能自动创建。还是有序的,不过虽然有序但是键值对不是数组,还是要记录最大值的。