第12届蓝桥杯 第一题:《直线》

2021年第12届蓝桥杯竞赛

第一题:《直线》

题目大意

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

在平面直角坐标系中,两点可以确定一条直线。

给定平面上 20 × 2120×21 个整点 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z}(x,y)∣0≤x<20,0≤y<21,xZ,yZ,即横坐标是 00 到

1919 (包含 00 和 1919) 之间的整数、纵坐标是 00 到 2020 (包含 00 和 2020) 之 间的整数的点。

请问这些点一共确定了多少条不同的直线。

解题思路

在平面直角坐标系中,俩点可以确定一条直线,那俩点有四个坐标值,我们不太好维护四个坐标值是否重复。

我们知道直线的表示方式中,除了俩点式,还有点斜式,点斜式的话, 一个点俩个坐标值和一个斜率值,三个值来确定唯一性,虽然不太好写但是还是勉强能跑出来。

选择y = kx + b 这条方程来代表直线。我们怎么表示K呢,我是定义一个string字符串,存储分子和分母,这样就不用担心小数的问题了。

如下面代码,先存储420个点到 list 集合中。

		int x = 19, y = 20;
		ArrayList<Integer> list = new ArrayList<Integer>();
		//存储420个点的坐标
		for (int i = 0; i <= x; i++) {
			for (int j = 0; j <= y; j++) {
				list.add(i*100 + j);
			}	

然后定义 HashSet 集合保存不重复的斜率和截距的直线(因为一个斜率和截距可以确定一条直线)

HashSet<String> set = new HashSet<String>();

然后嵌套两个 for 循环,遍历所有的点,(两层for循环代表第一个点和第二个点)

for (int i = 0; i < list.size(); i++) {
			for (int j = i+1; j < list.size(); j++) {

然后先找斜率:

                int a = list.get(i);
				int b = list.get(j);
				int x1 = a/100;
				int y1 = a%100;
				int x2 = b/100;
				int y2 = b%100;
				int down = x2 - x1;
				int up =   y2 - y1;
				//if (down!=0 && up !=0) {
					/**
					 * 求斜率
					 */
					int gcd = gcd(down, up);
					String s = (up / gcd) + "/" + (down / gcd);
///当分母为0使,代表斜率不存在,此时存储直线 (x = 0:代表过点(0,0),斜率不存在的直线)
					  if (down == 0) {
		                    set.add("x = " + x1);
		                    continue;
		                }

再求截距:

                     /**
					 * 求截距
					 */
					int y_down = y1 * down;
					int x_up   = x1 *up;
					int up2 = y_down - x_up;
					int gcd2 = gcd(up2, down);
					String s2 =(up2/gcd2) + "/" + (down/gcd2);

最后将截距和斜率字符串加入到 Set 集合;

set.add(s+" "+s2);

因为把分子分母分开存储,所以不要忘了约分,求分子和分母的最大公因数。

    public static int gcd(int m,int n){
		return n==0?m:gcd(n,m%n);
	}

完整代码:

import java.util.ArrayList;
import java.util.HashSet;
/*
 * 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
         在平面直角坐标系中,两点可以确定一条直线。
          给定平面上 20 × 2120×21​ 个整点
   {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z}(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z​,
           即横坐标是 00​ 到 1919​ (包含 00​ 和 1919​) 之间的整数
	 纵坐标是 00​ 到 2020​ (包含 00​ 和 2020​​) 之 间的整数的点。
	请问这些点一共确定了多少条不同的直线。
*/
public class 直线_1_2021 {
	public static void main(String[] args) {
		int x = 19, y = 20;
		ArrayList<Integer> list = new ArrayList<Integer>();
		//存储420个点的坐标
		for (int i = 0; i <= x; i++) {
			for (int j = 0; j <= y; j++) {
				list.add(i*100 + j);
			}
		}		
		HashSet<String> set = new HashSet<String>();
		//System.out.println(list.size());
		for (int i = 0; i < list.size(); i++) {
			int a = list.get(i);
			for (int j = i+1; j < list.size(); j++) {
				int b = list.get(j);
				int x1 = a/100;
				int y1 = a%100;
				int x2 = b/100;
				int y2 = b%100;
				int down = x2 - x1;
				int up =   y2 - y1;
				//if (down!=0 && up !=0) {
					/**
					 * 求斜率
					 */
					int gcd = gcd(down, up);
					String s = (up / gcd) + "/" + (down / gcd);
					/**
					 * 求截距
					 */
					  if (down == 0) {
		                    set.add("x = " + x1);
		                    continue;
		                }
					int y_down = y1 * down;
					int x_up   = x1 *up;
					int up2 = y_down - x_up;
					int gcd2 = gcd(up2, down);
					String s2 =(up2/gcd2) + "/" + (down/gcd2);
					/*
					 * 斜率和截距加入set集合
					 */
					set.add(s+" "+s2);
				//}
			}
		}	
		System.out.println(set.size());
	}
	//求最大公因数
    public static int gcd(int m,int n){
		return n==0?m:gcd(n,m%n);
	}
		
}

最终答案:40257。

上一篇:TypeScript学习-12 迭代器和生成器


下一篇:剑指offer-python:40.1~n整数中1出现的次数