首页 > 试题广场 >

能否完美地拼成矩形

[编程题]能否完美地拼成矩形
  • 热度指数:523 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
每条边不是平行于X轴就是平行于Y轴的矩形,可以用左下角和右上角的点来表示。比如{1, 2, 3, 4},表示的图形如下

给定一个N行4列的二维数组matrix,表示N个每条边不是平行于X轴就是平行于Y轴的矩形。想知道所有的矩形能否组成一个大的完美矩形。完美矩形是指拼出的整体图案是矩形,既不缺任何块儿,也没有重合部分
[要求]
时间复杂度为,额外空间复杂度为

输入描述:
第一行一个整数N,表示matrix的行数
接下来N行,每行4个整数分别表示矩形的左下角和右上角的点


输出描述:
若可以拼成一个大的完美矩形,输出"Yes", 否则输出"No"
示例1

输入

4
1 1 3 3
3 1 4 2
1 3 2 4
3 2 4 4

输出

No

说明

缺少{2, 3, 3, 4}这一块儿
示例2

输入

5
1 1 3 3
3 2 4 3
3 2 4 4
1 3 2 4
2 3 3 4

输出

No

说明

拼出的图案缺少{3, 1, 4, 2},并且{3, 2, 4, 2}是重合区域
示例3

输入

5
1 1 3 3
3 1 4 2
3 2 4 4
1 3 2 4
2 3 3 4

输出

Yes

备注:

#include <algorithm>
#include <vector>
#include <string>
#include <unordered_set>
using namespace std;


bool isPerfect(vector<vector<int>>&vec)
{
	int index1 = 0, index2 = 0;
	int area = 0;
	//找出边界
	for (int i = 0; i < vec.size(); i++)
	{
		area += (vec[i][2] - vec[i][0])*(vec[i][3] - vec[i][1]);
		if (vec[index1][0] >= vec[i][0] && vec[index1][1] >= vec[i][1])index1 = i;
		if (vec[index2][2] <= vec[i][2] && vec[index2][3] <= vec[i][3])index2 = i;
	}
	//检查边界是否正确,若有超出边界的直接false
	for (int i = 0; i < vec.size(); i++)
		if (vec[i][0]<vec[index1][0] || vec[i][1]<vec[index1][1] || vec[i][2]>vec[index2][2] || vec[i][3]>vec[index2][3])return false;

	//申请额外空间,若恰好为完美矩形,则除了边界外,每个小矩形顶点必重合且只重合两次->充必,不论两局部矩形是T字形还是什么型,只要最终组成一个矩形,大矩形内部的
	//所有小矩形的4个顶点必然重合两次,画图则知。
	unordered_set<string>set;
	for (int i = 0; i < vec.size(); i++)
	{
		string token = to_string(vec[i][0]) + "-" + to_string(vec[i][1]);
		string token3 = to_string(vec[i][0]) + "-" + to_string(vec[i][3]);
		string token2 = to_string(vec[i][2]) + "-" + to_string(vec[i][3]);
		string token4 = to_string(vec[i][2]) + "-" + to_string(vec[i][1]);
		if (set.find(token) != set.end())set.erase(token);
		else set.insert(token);
		if (set.find(token2) != set.end())set.erase(token2);
		else set.insert(token2);
		if (set.find(token3) != set.end())set.erase(token3);
		else set.insert(token3);
		if (set.find(token4) != set.end())set.erase(token4);
		else set.insert(token4);
	}
	for (auto it = set.begin(); it != set.end(); ++it)
	{
		int splitIndex = it->find("-");
		int first = atoi(it->substr(0, splitIndex).c_str());
		int second = atoi(it->substr(splitIndex + 1,it->size()-1-splitIndex).c_str());
		if (first == vec[index1][0] || first == vec[index2][2] || second == vec[index1][1] || second == vec[index2][3])continue;
		return false;
	}
	return true;
}

int main()
{
	int n;
	scanf("%d", &n);
	vector<vector<int>>vec(n);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			int tmp;
			scanf("%d", &tmp);
			vec[i].push_back(tmp);
		}
	}
	printf("%s", isPerfect(vec) ? "Yes" : "No");
}

发表于 2019-08-09 23:28:19 回复(2)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import java.util.Objects;


public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        Set<Point> counter = new HashSet<>();
        int mostDownX = Integer.MAX_VALUE;
        int mostDownY = Integer.MAX_VALUE;
        int mostUpX = Integer.MIN_VALUE;
        int mostUpY = Integer.MIN_VALUE;
        int sumOfArea = 0;

        for (int i = 0; i < n; i ++) {
            String[] strs = br.readLine().split(" ");
            int x1 = Integer.parseInt(strs[0]);
            int y1 = Integer.parseInt(strs[1]);
            int x2 = Integer.parseInt(strs[2]);
            int y2 = Integer.parseInt(strs[3]);

            mostDownX = Math.min(mostDownX, x1);
            mostDownY = Math.min(mostDownY, y1);
            mostUpX = Math.max(mostUpX, x2);
            mostUpY = Math.max(mostUpY, y2);
            sumOfArea += (x2 - x1) * (y2 - y1);

            Point leftDown = new Point(x1, y1);
            if (!counter.add(leftDown)) {
                counter.remove(leftDown);
            }

            Point leftUp = new Point(x1, y2);
            if (!counter.add(leftUp)) {
                counter.remove(leftUp);
            }

            Point rightDown = new Point(x2, y1);
            if (!counter.add(rightDown)) {
                counter.remove(rightDown);
            }

            Point rightUp = new Point(x2, y2);
            if (!counter.add(rightUp)) {
                counter.remove(rightUp);
            }
        }

        // 拼成矩形的四个顶点,需要且只能出现 1 次
        if (!counter.contains(new Point(mostDownX, mostDownY))
                || !counter.contains(new Point(mostDownX, mostUpY))
                || !counter.contains(new Point(mostUpX, mostUpY))
                || !counter.contains(new Point(mostUpX, mostDownY))
                || counter.size() != 4) {
            System.out.println("No");
            return;
        }

        if (sumOfArea == (mostUpX - mostDownX) * (mostUpY - mostDownY)) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
    }
}

class Point {
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        Point that = (Point) obj;
        return x == that.x && y == that.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x) ^ Objects.hash(y);
    }
}

编辑于 2024-03-25 21:46:23 回复(0)
思路:1.通过面积相等判断不缺任何块儿且不重合 2.通过判断单元块(1x1)是否在前只在一个矩形内,来判断是否缺块儿 
class FormRectangle{
private minLeft:number;
private maxRight:number;
private maxTop:number;
private minBottom:number;
public constructor(){
const matrix:number[][] = str.split(/\n/g).map((l)=>{
return l.split(/ /g).map(a=>Number(a));
});
console.log(matrix);
if(this.udgmentArea(matrix) && this.udgmentBlock(matrix)){
console.log('Yes');
}else{
console.log('No');
}
}
/**
* 判断面积
* @param {*} matrix
* @returns
*/
private udgmentArea(matrix:number[][]){
const firstRow = matrix[0];
let minLeft = firstRow[0];
let maxRight = firstRow[2];
let maxTop = firstRow[3];
let minBottom = firstRow[1];
let area = 0;
for(const row of matrix){
minLeft = Math.min(minLeft, row[0]);
maxRight = Math.max(maxRight, row[2]);
maxTop = Math.max(maxTop, row[3]);
minBottom = Math.min(minBottom, row[1]);
area += (row[2] - row[0]) * (row[3] - row[1]);
}
this.minLeft = minLeft;
this.maxRight = maxRight;
this.maxTop = maxTop;
this.minBottom = minBottom;
const maxarea = (maxTop - minBottom) * (maxRight - minLeft);
console.log( `${maxarea} === ${area}`);
return maxarea === area;
}
/**
* 通过判断单元块(1x1)是否在前只在一个矩形内
* @param matrix
* @returns
*/
private udgmentBlock(matrix:number[][]){
const minLeft = this.minLeft;
const maxRight = this.maxRight;
const maxTop = this.maxTop;
const minBottom = this.minBottom;
const rows = new Array(maxRight - minLeft).fill(1).map((val, index)=>{ return minLeft + index + 0.5;});
const rols = new Array(maxTop - minBottom).fill(1).map((val, index)=>{ return minBottom + index + 0.5;});
const list = [];
rows.forEach((a)=>{
rols.forEach((b)=>{
list.push([a, b]);
});
});
const m = new Array(matrix.length).fill(0);
return list.every((a:number[])=>{
return this.inBox(a, m, matrix);
});
}
/**
* 判断点 point 是否在matrix中的一个小块内
* @param point
* @param matrix
* @returns
*/
private inBox(point:number[], m:number[], matrix:number[][]){
const index = matrix.findIndex((r, index)=>{
if(m[index] === 0){
const [a, b, c, d] = r;
const [x, y] = point;
return (x - a) * (x - c) < 0 && (y - b) * (y - d) < 0;
}
return false;
});
// 去掉单元块,以减少比较次数 ,(容易出错, 最好改用标志位的形式)
const [a, b, c, d] = matrix[index];
// console.log([a, b, c, d], matrix, index);
if(index !== -1 && c - a === 1 && d - b === 1){
m[index] = 1;
}
return index !== -1;
}
}

发表于 2022-04-09 16:47:56 回复(0)

问题信息

上传者:小小
难度:
3条回答 3347浏览

热门推荐

通过挑战的用户

查看代码