第一次参加CSDN周赛,表现真的是一塌糊涂,所以把题目记下来,有空慢慢做。
打算以后把每一期的题目都做一遍
给你二维平面上两个由直线构成目边与坐标轴平行/垂直的矩形,请你计算并返回两个矩形覆盖的总面积。每个矩形由其左下顶点和右上顶点坐标表示:
第一个矩形由其左下顶点(ax1,ay1)和右上顶点(ax2,ay2)定义。第二个矩形由其左下顶点(bx1,by1)和右上顶点(bx2,by2)定义
参数限制:-10e4 <= ax1,ay1,ax2,ay2,bx1,by1,bx2,by2 <= 10e4
覆盖面积=两个矩形的面积相加然后减去重叠面积
本质上是求两个矩形的重叠面积
这个需要自己画个图,慢慢体会一下,重叠矩形的宽是bx2和ax2的最小值减去bx1和ax1的最大值,同理,矩形的高是by2和ay2的最小值减去by1和ay1的最大值
#include
#define min(x,y) ((x) < (y)? (x) : (y))
#define max(x,y) ((x) > (y)? (x) : (y))
// 求重合的面积
int get_coverage_area(int ax1, int ay1, int ax2, int ay2,
int bx1, int by1, int bx2, int by2)
{
int width = max(0, min(bx2, ax2) - max(bx1, ax1)); // 重叠矩形的宽
int height = max(0, min(by2, ay2) - max(by1, ay1));
return width * height;
}
小光买了一个可编程机器猫,机器猫初始位置在原点(0,0)。小伙伴事先给机器猫输入一串指令command,机器猫就会无限循环这条指今的步强进行移动。
指今有四种:U:向y轴正方向移动一格,R:向x轴正方向移动一格,D:向y轴负方向移动一格,L:向x轴负方向移动一格
不幸的是,在平面上还有一些遮挡物,他们的坐标用 barriers 表示。机器猫一旦碰到遮挡物就会被损毁。
给出command、barriers数组以及终点坐标,问:机器猫是否能安全到达终点
这个CSDN周赛题的输入方式对使用C语言太不友好了,从输入字符串中解析出每个参数都要费很大的功夫,这里就不写了
首先命令是循环的,每次循环都会到达一个点,这些点分别为A1,A2…An. 因为是命令是循环的,这些点一定是在一条直线上的断续的点。
在第一个命令循环中,我们可以得到两个信息
1.能够得到一个终点坐标a1,a1和原点确定一条直线,每一次循环的终点坐标就确定了,循环终点坐标确定,相当于起点坐标也确定了,因为起点坐标是前一次循环的终点坐标
2.在第一个命令循环中,也可以得到一次循环中,走过的路径中,相对于起点坐标在x轴和y轴4个方向的最大偏移量为u,d,l,r。
有了这两个信息,我们不用穷举每一次机器猫走过的路径,只要遍历可能经过障碍点和终点的某次循环就行了。
比如:每一次循环后的终点坐标是(2,3) f(n)=(2n,3n) ,最大偏移量:u=3,d=2,l=1,5,那么,每次循环可能经过的路径就在一个矩形之中,这个矩形的左下角坐标为(2n-l,3n-d),矩形的右上角坐标是(2n+r,3n+u),终点坐标是(x,y),只要在 2n-l <= x <= 3n+r and 2n-d <= y <= 3n+u的那次循环中,才有可能到终点。同理,障碍物坐标也是这样。
#include
#include
#include
#define min(x,y) ((x)<(y)? (x) : (y))
#define max(x,y) ((x)>(y)? (x) : (y))
#define coordinate_same(x1,y1,x2,y2) ((x1) == (x2) && (y1) == (y2))
// 移动后的坐标
#define MOVE(cmd,x,y) \
{\
switch(cmd)\
{\
case 'U':\
y += 1;\
break;\
case 'D':\
y -= 1;\
break;\
case 'L':\
x -= 1;\
break;\
case 'R':\
x += 1;\
break;\
} \
}
// 计算第几个循环可能经过某个坐标,n是一个范围
void get_cycle_num(int dest_x, int dest_y, int x1, int y1, int l, int r, int d,
int u, int *n_min, int * n_max)
{
// (x1*n-l <= x <= x1*n+r) and (y1*n-d <= y <= y1*n + u)
int xn_max = (dest_x+l)/x1; // x轴的n的最大值
int xn_min = (dest_x-r)/x1;
int yn_max = (dest_y+d)/y1; // y轴的n的最大值
int yn_min = (dest_y-u)/y1;
*n_max = min(xn_max, yn_max); // 综合x轴和y轴,n可以取的最大值
*n_min = max(xn_min, yn_min);
printf("xn_min=%d,xn_max=%d,yn_min=%d,yn_max=%d,n_min=%d,n_max=%d\n",
xn_min,xn_max,yn_min,yn_max,*n_min,*n_max);
}
// 检查当前坐标是否是终点或者是障碍物坐标
// return: 0:都不是 1:是终点 2:是障碍物
int check_dest_and_obstacle(int x, int y, int dest_x, int dest_y, int barriers_x[],
int barriers_y[], int barrier_num)
{
if (coordinate_same(x,y,dest_x,dest_y))
return 1;
for (int i = 0; i < barrier_num; i++)
{
if (coordinate_same(x,y,barriers_x[i],barriers_y[i]))
return 2;
}
return 0;
}
/**
* @函数名称: can_arrive_destination
* @功能描述: 判断是否能到达终点
* @输入参数:
* command: 指令集,U:向y轴正方向移动一格,R:向x轴正方向移动一格,D:向y轴负方向移动一格,L:向x轴负方向移动一格
* dest_x,dest_y: 终点坐标
* barriers_x,barriers_y: 障碍物的x坐标和y坐标
* barrier_num: 障碍物的个数
*/
bool can_arrive_destination(char *command, int dest_x, int dest_y, int barriers_x[],
int barriers_y[], int barrier_num)
{
int x, y; // 当前坐标
int x1, y1; // 第一次命令执行后的位置
int start_x = 0, start_y = 0; // 初始点坐标
int d = 0, u = 0, l = 0, r = 0;
char *p;
int x_shift, y_shift;
// 1.计算第一次执行完整命令后移动的终点和各个方向的偏移量
p = command;
x = start_x;
y = start_y;
int count = 0;
while(*p)
{
MOVE(*p,x,y);
x_shift = x - start_x;
y_shift = y - start_y;
if (x_shift > 0 && x_shift > r)
r = x_shift;
else if (x_shift < 0 && -x_shift > l)
l = -x_shift;
if (y_shift > 0 && y_shift > u)
u = y_shift;
else if (y_shift < 0 && -y_shift > d)
d = -y_shift;
// printf("%c,x=%d,y=%d\n",*p,x,y);
p++;
count++;
}
x1 = x;
y1 = y;
printf("first move:(%d,%d),u=%d,d=%d,l=%d,r=%d\n",x,y,u,d,l,r);
// 2.计算终点是在第几次命令循环
int n_min, n_max;
get_cycle_num(dest_x,dest_y,x1,y1,l,r,d,u,&n_min,&n_max);
// 如果没有满足的n,则说明一定走不到终点
if (n_max < n_min)
return false;
// 3.在可能经过终点的循环中遍历是否能到达终点
bool succ = false;
for (int n = n_min; n <= n_max; n++)
{
x = x1 * n;
y = y1 * n;
p = command;
// 使用do while是因为需要检查起点坐标
do
{
int res = check_dest_and_obstacle(x,y,dest_x,dest_y,barriers_x,barriers_y,barrier_num);
if (1 == res)
{
succ = true;
break;
}
else if (2 == res) // 会经过障碍物,直接失败
{
return false;
}
MOVE(*p,x,y);
p++;
}while(*p);
if (true == succ)
break;
}
// printf("000000000\n");
if (!succ)
return false;
// 4.即使第n次循环能到达终点,但是如果第1-(n-1)次循环经过了障碍物也不能到达终点
int barrier_min_n[200]; // 这里可以申请动态内存来节省空间和避免越界,200已经满足题目的要求了
int barrier_max_n[200];
int barrier_n_upper = n_min - 1; // 循环上限
// 计算可能经过障碍物是第几次循环
for (int i = 0; i < barrier_num; i++)
{
// 4.1计算每个障碍物是在第几次命令循环中可能到达的
int n_min, n_max;
get_cycle_num(barriers_x[i],barriers_y[i],x1,y1,l,r,d,u,&n_min,&n_max);
// n的范围必须小于 barrier_n_upper
if (n_max < n_min || n_min > barrier_n_upper)
{
barrier_min_n[i] = -1; // 用-1表示不能能经过障碍物
barrier_max_n[i] = -1;
}
else
{
barrier_min_n[i] = n_min;
barrier_max_n[i] = min(n_max, barrier_n_upper);
}
}
for (int i = 0; i < barrier_num; i++)
{
if (-1 == barrier_min_n[i])
continue;
// 检查是否经过障碍物
for (int n = barrier_min_n[i]; n <= barrier_max_n[i]; n++)
{
x = x1 * n;
y = y1 * n;
p = command;
do
{
if (coordinate_same(x,y,barriers_x[i],barriers_y[i]))
return false;
MOVE(*p,x,y);
p++;
}while(*p);
}
}
return true;
}
int main()
{
char command[] = "URR"; // 命令
int x = 3, y = 2; // 终点坐标
int barriers_x[200] = {2}; // 障碍物x轴坐标
int barriers_y[200] = {2}; // 障碍物y轴坐标
int barrier_num = 1; // 障碍物坐标的个数
if (can_arrive_destination(command,x,y,barriers_x,barriers_y,barrier_num))
printf("true");
else
printf("false");
return 0;
}