AcWing 2013.三条线

17 篇文章 0 订阅
这篇博客介绍了如何使用Java解决一个算法问题,即判断农夫约翰能否用三个摄像头覆盖其所有奶牛的位置。通过分析奶牛坐标,确定可能的直线布局(平行于x轴或y轴),并进行有效覆盖的策略枚举,最终判断是否能用三条直线实现全面覆盖。博客详细阐述了解题思路和Java代码实现过程。
摘要由CSDN通过智能技术生成

题目

农夫约翰想用他购买的新监视系统监视他的 N 头奶牛。

第 i 头奶牛位于具有整数坐标的位置 (xi,yi)。

没有两头奶牛占据相同的位置。

约翰的监视系统包含三个特殊的摄像头,每个摄像头都能够沿垂直或水平线观察一条线上所有的奶牛。

请确定约翰是否可以通过合理设置三个摄像头的摆放位置,以便他可以监视所有 N 头奶牛。

也就是说,请确定是否可以通过三条垂直或水平摆放的线将所有 N 个奶牛所在位置全部覆盖。

输入格式
第一行包含整数 N。

接下来 N 行,每行包含两个整数 xi,yi,表示一头奶牛所在位置的横纵坐标。

输出格式
如果可以通过三条垂直或水平摆放的线将所有 N 个奶牛所在位置全部覆盖,请输出 1,否则输出 0。

数据范围
1 ≤ N ≤ 50000,
0 ≤ xi, yi ≤109
输入样例:

6
1 7
0 0
1 2
2 0
1 4
3 4

输出样例:

1

样例解释
y=0,x=1,y=4 可满足将所有奶牛位置覆盖。

解题思路

用三条直线覆盖所有的点,有以下几种情形:
(1)三条平行于 x 轴的直线
(2)三条平行于 y 轴的直线
(3)一条平行于 x 轴的直线和两条平行于 y 轴的直线
(4)一条平行于 y 轴的直线和两条平行于 x 轴的直线

所以我们先记录 x 位置出现的数字和 y 位置出现的数字
如果 x 出现的数字数量小于等于 3,那么我们可以用小于等于三条平行于 y 轴的直线覆盖,即情形 2
如果 y 出现的数字数量小于等于 3,那么我们可以用小于等于三条平行于 x 轴的直线覆盖,即情形 1

枚举 x 出现的所有数字,先用 x = xi 这条直线覆盖,将剩下未被覆盖的牛用平行于 x 轴的直线覆盖
若所需要的直线数小于等于三,则该方案可行,有解

枚举 y 出现的所有数字,先用 y = yi 这条直线覆盖,将剩下未被覆盖的牛用平行于 y 轴的直线覆盖
若所需要的直线数小于等于三,则该方案可行,有解

Java代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;

public class Main {
	
	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(System.out);
		
		int n = Integer.parseInt(in.readLine());	// 牛的数量
		
		Cow[] cows = new Cow[n];
		Set<Integer> rowSet = new HashSet<Integer>();	// 存储行的位置
		Set<Integer> columnSet = new HashSet<Integer>();	// 存储列的位置
		
		boolean flag = false;	// 初始状态为不可用三条线覆盖
		
		for(int i = 0; i < n; i++) {
			String str = in.readLine();
			int x = Integer.parseInt(str.split(" ")[0]);
			int y = Integer.parseInt(str.split(" ")[1]);
			
			cows[i] = new Cow(x, y);
			rowSet.add(x);
			columnSet.add(y);
		}
		
		// 如果行的位置数或者列的位置数小于等于三,则说明可以用三条或三条以下的平行直线覆盖
		if(rowSet.size() <= 3 || columnSet.size() <= 3) {
			out.println(1);
			out.flush();
			return ;
		}
		
		// 先用一条平行于 x 轴的直线覆盖
		for(int row : rowSet) {
			Set<Integer> temp = new HashSet<Integer>();
			for(int i = 0; i < n; i++) {
				if(cows[i].x != row) temp.add(cows[i].y);	// 如果该点未被横线覆盖,则用一条平行于 y 轴的直线覆盖
				if(temp.size() > 2) break;	// 若该方案覆盖的平行于 y 轴的直线已经超过两条,说明该方案不可行
			}
			if(temp.size() <= 2) {
				flag = true;	// 若该方案覆盖的平行于 y 轴的直线小于等于两条,说明该方案可行
				break;
			}
		}
		
		if(flag) {
			out.print(1);
			out.flush();
			return;
		}
		
		// 再用一条平行于 y 轴的直线覆盖
		for(int column : columnSet) {
			Set<Integer> temp = new HashSet<Integer>();
			for(int i = 0; i < n; i++) {
				if(cows[i].y != column) temp.add(cows[i].x);	// 如果该点未被覆盖,则用一条平行于 x 轴的直线覆盖
				if(temp.size() > 2) break ;	// 若该方案覆盖的平行于 x 轴的直线已经超过两条,说明该方案不可行
			}
			if(temp.size() <= 2) {
				flag = true;	// 若该方案覆盖的平行于 x 轴的直线小于两条,则说明该方案可行
				break;
			}
		}
		
		if(flag) out.print(1);
		else out.print(0);
		out.flush();
	}
	
	public static class Cow{
		public int x;	// 牛所在的行
		public int y;	// 牛所在的列
		
		public Cow() {
			this.x = 0;
			this.y = 0;
		}
		
		public Cow(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值