重庆赛区ACM热身题 8531. KD's fear

孤街醉人 提交于 2019-12-06 19:58:49

重庆赛区ACM热身题 8531. KD’s fear

前面博主把这个热身赛上的提交通过率最低的一道题解决了,下面博主将在解决一下这道编程题里面的一道几何题把,首先看见acm群里面大家用什么什么向量,二分法求这个点是否在这个凸多边行内,其实哪有这么高深,我认为就用初高中的知识就够了 就是一个点与线之间的关系;
哦 对哈题目还没说,这个题目呢意思很简单就是内部机理就是判断一个点是否在这个多变形内;

  • 首先呢我们来看一下这个图:
    解释
    我们看哈 其实我们要保证这个M点(Boss所在坐标)要在这个凸多边形内部其实就只需要保证M点在跟这个多边形的每一条边保持在同一侧就行了 我们看哈 因为输入保证是逆时针输入所以我们以A点为起点首先我们以A→B这条边来看 M 点是在AB这条边的左边 所以呢就是要保证M点在其他的每条边的左边即可保证M点在这个凸多边型内。我们学过直线方程的都知道 要想判断一个点是否在这条直线上或者在这条直线右 或者左 那么即是将这个点带入这个方程看这个值与0之间的关系 如果大于0那么即是这个点在直线的右边,那么小于零即是在这个直线的左边,等于零呢就是在这个直线上。
    有了这个逻辑那么就好办事了。两个点我们可以确定一个直线方程 ,我们用第一个点与 个点组成方程,第二个点又与第三个点组成方程,第三个点与第四个点组成方程,…… 直到第8个点我们与第一个点组成一个方程。
    两点确定一个方程的公式呢就是:
    (y1-y2)*x +(x1-x2)*y -(y1-y2)*x1 + (x1-x2)*y1 = 0
    我们让:
    a = (y1-y2)
    b = (x1-x2)
    c = (x1-x2)*y1 -(y1-y2)*x1
    这样就便于后面的验证计算 我用一个名字为equation的double 二维数组来存储每条边的a,b,c的值
    代码:
public static void etl(ArrayList<String[]> D) {
		for(int i=1;i<D.size();i++) {
			double a,b,c;
			
			if(i == 8) {
				a = Integer.parseInt(D.get(i)[2]) -Integer.parseInt(D.get(1)[1]);
				b= Integer.parseInt(D.get(i)[1]) -Integer.parseInt(D.get(0)[1]);
				c = b*Integer.parseInt(D.get(i)[2]) -a*Integer.parseInt(D.get(i)[1]);
			}
			else {
				a = Integer.parseInt(D.get(i)[2]) -Integer.parseInt(D.get(i+1)[2]);
				b= Integer.parseInt(D.get(i)[1]) -Integer.parseInt(D.get(i+1)[1]);
				c = b*Integer.parseInt(D.get(i)[2]) -a*Integer.parseInt(D.get(i)[1]);
			}
			equation[i-1][0] = a;
			equation[i-1][1] = b;
			equation[i-1][2] = c;
			vector[i-1][0] = -a;
			vector[i-1][1] = -b;
			
		}
	}

因为开始我以为这道题要进行是否为凸多边型的判断所以定义了一个vector的二维数组来存放每一个边向量,显然这道题是不会用到的,既然说到了还是提一下判断是否为凸多边型的方法把,毕竟多学点是好的,如果没兴趣可以直接跳过到最后 直接看代码。
下面是判断是否为凸多边型的办法
最容易让人想到的方法就是 凸多边形的外角和为360 度,显然在这里运用在我们程序里面是不可能的,那计算量太大了,涉及到三角函数的余弦定理 正弦定理 反三角函数代换 显然是不切实际的 那我们使用另一种方法 向量分析法;
2
这个方法也很简单原理其实也差不多,我们首先用向量AB·BC (注意是点积而不是 ×乘) 这样我们得到一个值 这个值呢我们又拿来跟0进行比较 我们都熟悉的是如果向量积为0的话那么表示这两个向量垂直,那么大于零呢 就是两个向量的夹角小于90度 那么在图中通过几何关系即可发现在向量的夹角小于90度时那么这个多边形的夹角即大于90度 是互补的也就是说多边形的夹角等于180度 - 向量夹角度数

好有了这个关系我们就可以进行判断了将vector数组进行遍历一次 最后一个元素和第一个元素组合判断向量积于零的关系保证所有向量积都大于零即可保证多边形为凸多边形;
下面是我整个程序的代码:

package proje_1;

import java.util.ArrayList;
import java.util.Scanner;

class acm_9 {
	private static double[][] vector = new double[8][2];
	private static double[][] equation = new double[8][3];
	public static ArrayList<String[]> input(){
		Scanner scanner = new Scanner(System.in);
		ArrayList<String[]> data = new ArrayList<String[]>();
		for(int i = 0;i<9;i++) {
			String[] point = scanner.nextLine().split(" ");
			data.add(point);
		}
		return data;
	}
	public static void etl(ArrayList<String[]> D) {
		for(int i=1;i<D.size();i++) {
			double a,b,c;
			
			if(i == 8) {
				a = Integer.parseInt(D.get(i)[2]) -Integer.parseInt(D.get(1)[1]);
				b= Integer.parseInt(D.get(i)[1]) -Integer.parseInt(D.get(0)[1]);
				c = b*Integer.parseInt(D.get(i)[2]) -a*Integer.parseInt(D.get(i)[1]);
			}
			else {
				a = Integer.parseInt(D.get(i)[2]) -Integer.parseInt(D.get(i+1)[2]);
				b= Integer.parseInt(D.get(i)[1]) -Integer.parseInt(D.get(i+1)[1]);
				c = b*Integer.parseInt(D.get(i)[2]) -a*Integer.parseInt(D.get(i)[1]);
			}
			equation[i-1][0] = a;
			equation[i-1][1] = b;
			equation[i-1][2] = c;
			vector[i-1][0] = -a;
			vector[i-1][1] = -b;
			
		}
	}
	
	public static boolean judge(double x,double y) {
		for(int i =0 ;i<equation.length;i++) {
			if(equation[i][0]*x + equation[i][1]*y + equation[i][2] >= 0) {
				return false;
			}
		}
		return true;
	}
	
	
	public static void main(String[] args) {
		ArrayList<String[]> data = input();
		etl(data);
		if(judge(Integer.parseInt(data.get(0)[0]), Integer.parseInt(data.get(0)[1]))) {
			System.out.println("WTF!");
		}

	}

}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!