平面内有n个矩形, 第i个矩形的左下角坐标为(x1[i], y1[i]), 右上角坐标为(x2[i], y2[i])。
如果两个或者多个矩形有公共区域则认为它们是相互重叠的(不考虑边界和角落)。
请你计算出平面内重叠矩形数量最多的地方,有多少个矩形相互重叠。
平面内有n个矩形, 第i个矩形的左下角坐标为(x1[i], y1[i]), 右上角坐标为(x2[i], y2[i])。
如果两个或者多个矩形有公共区域则认为它们是相互重叠的(不考虑边界和角落)。
请你计算出平面内重叠矩形数量最多的地方,有多少个矩形相互重叠。
输入包括五行。
第一行包括一个整数n(2 <= n <= 50), 表示矩形的个数。
第二行包括n个整数x1[i](-10^9 <= x1[i] <= 10^9),表示左下角的横坐标。
第三行包括n个整数y1[i](-10^9 <= y1[i] <= 10^9),表示左下角的纵坐标。
第四行包括n个整数x2[i](-10^9 <= x2[i] <= 10^9),表示右上角的横坐标。
第五行包括n个整数y2[i](-10^9 <= y2[i] <= 10^9),表示右上角的纵坐标。
输出一个正整数, 表示最多的地方有多少个矩形相互重叠,如果矩形都不互相重叠,输出1。
2 0 90 0 90 100 200 100 200
2
/* 无论何种情况,重叠区域也是四条边组成。 而且是取自与n的矩形中的四条。 所以遍历边的交点即可。 */ import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] x1 = new int[n]; int[] y1 = new int[n]; int[] x2 = new int[n]; int[] y2 = new int[n]; int xmin = Integer.MAX_VALUE; int xmax = Integer.MIN_VALUE; int ymin = Integer.MAX_VALUE; int ymax = Integer.MIN_VALUE; for (int i = 0; i < n; i++) x1[i] = in.nextInt(); for (int i = 0; i < n; i++) y1[i] = in.nextInt(); for (int i = 0; i < n; i++) x2[i] = in.nextInt(); for (int i = 0; i < n; i++) y2[i] = in.nextInt(); int ans = 0; int cnt = 0; for (int x : x1) for (int y : y1) { for (int i = 0; i < n; i++) { if (x >= x1[i] && x < x2[i] && y >= y1[i] && y < y2[i]) cnt++; } if (cnt > ans) ans = cnt; cnt = 0; } System.out.println(ans); } }
注意判断重叠矩形数量最多的地方:遍历所有可能包含的点,看一下有多少矩形包含它
注:重叠数量最多的地方肯定是一块矩形区域误区:A和B交,B和C交,但是A不和C交 --- B同时和A,C交, 但是重叠区域只为1
代码如下:
import sys
lines = sys.stdin.readlines()
n = int(lines[0])
x1 = list(map(int,lines[1].split()))
y1 = list(map(int,lines[2].split()))
x2 = list(map(int,lines[3].split()))
y2 = list(map(int,lines[4].split()))
# 遍历所有点的组合(包含了矩形所有角以及交点),看一下有多少矩形包含它
res = 1
for x in x1+x2:
for y in y1+y2:
cnt = 0
for i in range(n):
if x > x1[i] and y > y1[i] and x <= x2[i] and y <= y2[i]:
cnt += 1
res = max(res,cnt)
print(res)
O(n^2logn)算法。
思路是首先对所有矩形排序,按照底边坐标值升序。
考虑到若将平面按照所有矩形的的底边坐标值横向划分,每个划分中的最大重合情况总是出现在该划分底部,且等价一维的区间重合问题。如图所示:
因此,我们每次迭代将下一个或多个底边坐标值最低的矩阵加入队列,并将整个在当前最低坐标值之下的矩形从队列中移除,然后用区间重合的算法计算队列中矩形在目前划分的重合数量。
以下是代码:
#include <iostream> #include <cstdio> #include <vector> #include <string> #include <algorithm> #include <map> #include <limits.h> using namespace std; // square overlap class Square{ public: int left, right, up, down; bool operator <(const Square &x){ return down < x.down; } }; bool leftto(Square a, Square b){ return a.left < b.left; } void eraselower(vector<Square> &a, int ybound){ int deln = 0, i = 0, n = a.size(); while(i + deln < n){ if(a[i].up<=ybound) swap(a[i], a[n-(++deln)]); else ++i; } a.erase(a.end()-deln, a.end()); } int main(){ int n; cin>>n; vector<Square> sqs(n), row; for(int i=0; i<n; ++i) cin>>sqs[i].left; for(int i=0; i<n; ++i) cin>>sqs[i].down; for(int i=0; i<n; ++i) cin>>sqs[i].right; for(int i=0; i<n; ++i) cin>>sqs[i].up; sort(sqs.begin(), sqs.end()); int sn = 0, curdown = 0, res = 0; while(sn<n){ curdown = sqs[sn].down; while(sn<n && sqs[sn].down == curdown) row.push_back(sqs[sn++]); eraselower(row, curdown); sort(row.begin(), row.end(), leftto); vector<int> rights; for(Square x:row){ rights.erase(rights.begin(), upper_bound(rights.begin(), rights.end(), x.left)); rights.insert(upper_bound(rights.begin(), rights.end(), x.right), x.right); if(res < rights.size()) res = rights.size(); } } cout<<res<<endl; }
#include <bits/stdc++.h> using namespace std; const int N = 55; int x1[N],y11[N],x2[N],y2[N],X[2*N],Y[2*N]; int mp[2*N][2*N],p,q,lx,ly,rx,ry; void color(){ ///将矩形出现在方格中的点全部+1 for(int i=lx+1;i<=rx;i++)for(int j=ly+1;j<=ry;j++){ ///由于边界不算,所以从lx+1开始 mp[i][j]++; } } int main(){ int n; scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",&x1[i]),X[i]=x1[i]; for(int i=0;i<n;i++)scanf("%d",&y11[i]),Y[i]=y11[i]; for(int i=0;i<n;i++)scanf("%d",&x2[i]),X[i+n]=x2[i]; for(int i=0;i<n;i++)scanf("%d",&y2[i]),Y[i+n]=y2[i]; sort(X,X+2*n); ///离散化过程 sort(Y,Y+2*n); p = unique(X,X+2*n)-X; q = unique(Y,Y+2*n)-Y; for(int i=0;i<n;i++){ lx = lower_bound(X,X+p,x1[i])-X; ///查询离散化之后出现在方格的左下角和右上角坐标 ly = lower_bound(Y,Y+q,y11[i])-Y; rx = lower_bound(X,X+p,x2[i])-X; ry = lower_bound(Y,Y+q,y2[i])-Y; color(); } int ans = 1; for(int i=0;i<p;i++)for(int j=0;j<q;j++)ans = max(ans,mp[i][j]); printf("%d\n",ans); return 0; }
#include <iostream> #include <cstdio> #include <vector> #include <string> #include <queue> #include <cstring> #include <utility> #include <climits> #include <unordered_map> #include <algorithm> #include <stack> #include <cmath> #include <map> #include <numeric> #define LL long long #define M 1000000007 #define M2 998244353 #define MAXN 105 #define eps 1e-7 using namespace std; struct Node { int s, e, val, tag; }; Node seg[MAXN*4]; void build(int idx, int s, int e) { seg[idx].s = s, seg[idx].e = e; int m = (s+e)/2; if (s == e) return; build(idx*2, s, m), build(idx*2+1, m+1, e); } void update(int idx, int start, int end, int off) { //cout << "update:" << start << "," << end << ":" << off << endl; if (start == seg[idx].s && end == seg[idx].e) { seg[idx].tag += off; seg[idx].val += off; return; } int m = (seg[idx].s+seg[idx].e)/2; if (seg[idx].tag) { update(idx*2, seg[idx].s, m, seg[idx].tag); update(idx*2+1, m+1, seg[idx].e, seg[idx].tag); seg[idx].tag = 0; } if (end <= m) update(idx*2, start, end, off); else if (start > m) update(idx*2+1, start, end, off); else { update(idx*2, start, m, off); update(idx*2+1, m+1, end, off); } seg[idx].val = max(seg[idx*2].val, seg[idx*2+1].val); } int query(int idx, int start, int end) { if (seg[idx].s == start && seg[idx].e == end) { return seg[idx].val; } int m = (seg[idx].s+seg[idx].e)/2; if (seg[idx].tag) { update(idx*2, seg[idx].s, m, seg[idx].tag); update(idx*2+1, m+1, seg[idx].e, seg[idx].tag); seg[idx].tag = 0; } if (end <= m) return query(idx*2, start, end); else if (start > m) return query(idx*2+1, start, end); else return max(query(idx*2, start, m), query(idx*2+1, m+1, end)); } int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; vector<int> x1(n), y1(n), x2(n), y2(n); vector<int> ys; for (int i = 0; i < n; i++) cin >> x1[i]; for (int i = 0; i < n; i++) cin >> y1[i]; for (int i = 0; i < n; i++) cin >> x2[i]; for (int i = 0; i < n; i++) cin >> y2[i]; for (int i = 0; i < n; i++) ys.push_back(y1[i]), ys.push_back(y2[i]); sort(ys.begin(), ys.end()); ys.resize(unique(ys.begin(), ys.end()) - ys.begin()); unordered_map<int, int> y2i; for (int i = 0; i < ys.size(); i++) y2i[ys[i]] = i; vector<vector<int>> v; for (int i = 0; i < n; i++) { v.push_back({x1[i], 1, y2i[y1[i]], y2i[y2[i]]}); v.push_back({x2[i], -1, y2i[y1[i]], y2i[y2[i]]}); } sort(v.begin(), v.end(), [](const vector<int>& v1, const vector<int>& v2) { return v1[0] < v2[0] || v1[0] == v2[0] && v1[1] < v2[1]; }); int res = 0; build(1, 0, ys.size()); int lastx = INT_MIN; for (auto& vv: v) { if (lastx == INT_MIN && vv[1] < 0) continue; //cout << vv[0] << "," << vv[1] << "," << vv[2] << "," << vv[3] << endl; if (vv[0] != lastx) { //cout << query(1, 0, ys.size()) << endl; res = max(res, query(1, 0, ys.size())); lastx = vv[0]; } update(1, vv[2], vv[3]-1, vv[1]); } //cout << query(1, 0, ys.size()) << endl; res = max(res, query(1, 0, ys.size())); cout << res << endl; return 0; }
import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Scanner; class edge implements Comparable{ Integer left; Integer right; Integer height; Integer value; edge(int left,int right,int height,int value){ this.left=left; this.right=right; this.height=height; this.value=value; } @Override public int compareTo(Object o) { return Integer.compare(height,((edge)o).height); } } public class Main { public static void main(String[] args){ ArrayList<Integer> xAxial=new ArrayList<Integer>(); ArrayList<edge> allEdges=new ArrayList<>(); Scanner in=new Scanner(System.in); int n=in.nextInt(); int[] x1=new int[n]; int[] x2=new int[n]; int[] y1=new int[n]; int[] y2=new int[n]; for(int i=0;i<n;++i){ x1[i]=in.nextInt(); xAxial.add(x1[i]); } for(int i=0;i<n;++i){ y1[i]=in.nextInt(); } for(int i=0;i<n;++i){ x2[i]=in.nextInt(); xAxial.add(x2[i]); } for(int i=0;i<n;++i){ y2[i]=in.nextInt(); } for(int i=0;i<n;++i){ allEdges.add(new edge(x1[i],x2[i],y1[i],1)); allEdges.add(new edge(x1[i],x2[i],y2[i],-1)); } Collections.sort(xAxial); Collections.sort(allEdges); ArrayList<Integer> count=new ArrayList<Integer>(); for(int i=0;i!=xAxial.size()-1;++i) count.add(0); int result=1; for(edge tmp : allEdges){ Integer index=xAxial.indexOf(tmp.left); while(xAxial.get(index)<tmp.right){ count.set(index,count.get(index)+tmp.value); if(count.get(index)>result){ result=count.get(index); } ++index; } } System.out.println(result); } }
#include <bits/stdc++.h> using namespace std; int main() { //读取输入 int n; cin>>n; int x1[n],y1[n],x2[n],y2[n];//左下x,左下y,右上x,右下y for(int i = 0;i<n;i++) cin>>x1[i]; for(int i = 0;i<n;i++) cin>>y1[i]; for(int i = 0;i<n;i++) cin>>x2[i]; for(int i = 0;i<n;i++) cin>>y2[i]; int result = 0; //二维转一维,遍历左下角点的x和y,看这些点在多少个矩形内 for(int x: y1) for(int y: y1) { int cnt =0; for(int j=0;j<n;j++) { //注意判断条件,一开一闭,否则两个完全重合的矩形会多计算一次 if(x>=x1[j]&&x<x2[j]&&y>=y1[j]&&y<y2[j]) cnt++; } result = max(cnt,result); } cout<<result<<endl; return 0; }
import sys n=int(sys.stdin.readline().strip()) x1=list(map(int,sys.stdin.readline().strip().split())) y1=list(map(int,sys.stdin.readline().strip().split())) x2=list(map(int,sys.stdin.readline().strip().split())) y2=list(map(int,sys.stdin.readline().strip().split())) res = 1 for x in x1+x2: for y in y1+y2: cnt = 0 for i in range(n): if x > x1[i] and y > y1[i] and x <= x2[i] and y <= y2[i]: cnt += 1 res = max(res,cnt) print(res)
""" 重叠的区域角横坐标x必然是【x1,x2】中某个值 重叠的区域角横坐标y必然是【y1,y2】中某个值 遍历所有坐标点(x,y),由于重叠不考虑边界和角落 在 x_range, y_range = x ± δ, y ± δ (δ< 1) x1[i] < x_range < x2[i] and y1[i] < y_range < y2[i] 范围内计算重叠个数 或者 x1[i] < x <= x2[i] and y1[i] < y <= y2[i] ,等号的位置等同于上式的±号。 取所有坐标点最大的重叠个数即为所求 """ import sys if __name__ == "__main__": # sys.stdin = open('input.txt', 'r') n = int(input().strip()) x1 = list(map(int, input().strip().split())) y1 = list(map(int, input().strip().split())) x2 = list(map(int, input().strip().split())) y2 = list(map(int, input().strip().split())) ans = 1 for x in x1 + x2: for y in y1 + y2: x_range, y_range = x - 0.1, y - 0.1 cnt = 0 for i in range(n): if x1[i] < x_range < x2[i] and y1[i] < y_range < y2[i]: # if x1[i] < x <= x2[i] and y1[i] < y <= y2[i]: cnt += 1 ans = max(ans, cnt) print(ans)
#include <bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; int x1[n],y1[n],x2[n],y2[n]; for(int i=0;i<n;i++) cin>>x1[i]; for(int i=0;i<n;i++) cin>>y1[i]; for(int i=0;i<n;i++) cin>>x2[i]; for(int i=0;i<n;i++) cin>>y2[i]; int cnt = 0, s = 0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ for(int k=0;k<n;k++) if(x1[i]>=x1[k] && x1[i]<x2[k] && y1[j]>=y1[k] && y1[j]<y2[k]) cnt++; s = max(s, cnt); cnt = 0; } } cout<<s<<endl; return 0; }
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int res=0; int n; cin>>n; vector<int> x1(n); vector<int> y1(n); vector<int> x2(n); vector<int> y2(n); vector<int> x(2*n); vector<int> y(2*n); for(int i=0;i<n;i++) { cin>>x1[i]; x[i]=x1[i]; } for(int i=0;i<n;i++) { cin>>y1[i]; y[i]=y1[i]; } for(int i=0;i<n;i++) { cin>>x2[i]; x[n+i]=x2[i]; } for(int i=0;i<n;i++) { cin>>y2[i]; y[n+i]=y2[i]; } //总结所有矩形相交的情况,可以通过某一矩形的的边角点或者某一矩形和另外一矩形的交点 //在几个矩形范围内来计量重叠矩形个数 for(int i=0;i<2*n;i++) for(int j=0;j<2*n;j++) { int tmp=0; //去掉无意义的射线相交点,虽然不去掉也不会影响结果,但终究是无意义的情况 if(!(x1[i%n]<=x[i]&&x[i]<=x2[i%n]&&y1[i%n]<=y[j]&&y[j]<=y2[i%n])) continue; //遍历所有矩形,看我们列举出的点最多被几个矩形包含 for(int k=0;k<n;k++) { //这里只有一个方向是包含的,因为对于边界和角落相交并不属于矩形重叠 if(x1[k]<=x[i]&&x[i]<x2[k]&&y1[k]<=y[j]&&y[j]<y2[k]) tmp++; } res=max(res,tmp); } cout<<res; }
#include<iostream> #include<vector> using namespace std; void solver(){ int n; cin >> n; vector<int> x1(n,0);//x1,x2表示左下角的点的横纵坐标 vector<int> x2(n,0); vector<int> y1(n,0);//y1,y2表示左下角的点的横纵坐标 vector<int> y2(n,0); vector<int> a(2*n,0);//存储所有的横坐标 vector<int> b(2*n,0);//存储左右的纵坐标 for(int i = 0; i < n; i++) { cin >> x1[i]; a[i] = x1[i]; } for(int i = 0; i < n; i++) { cin >> y1[i]; b[i] = y1[i]; } for(int i = 0; i < n; i++) { cin >> x2[i]; a[i+n] = x1[i]; } for(int i = 0; i < n; i++) { cin >> y2[i]; b[i+n] = y1[i]; } int ans = 0; //遍历所有横纵坐标的可能组合,判断该点位于多少矩形内,则对应的矩形互相重叠 for(int x =0;x<2*n;x++) { for(int y=0;y<2*n ;y++) { int cnt = 0; for(int i = 0; i < n; i++) { //包含左下角坐标的等号是有可能两个矩阵完全重合 if(x1[i] <= a[x] && y1[i] <= b[y] && x2[i] > a[x] && y2[i] > b[y]) cnt++; } ans = max(ans, cnt); } } cout << ans << endl; } int main(){ solver(); return 0; }
#include<bitset> #include<stdio.h> using namespace std; const int maxn = 50+5; bitset<maxn> E[maxn]; int x1[maxn],y1[maxn],x2[maxn],y2[maxn]; inline void addEdge(int x,int y){ E[x].set(y); E[y].set(x); } bool in(int xx,int yy,int w){ if (xx>x1[w]&&xx<x2[w]&&yy>y1[w]&&yy<y2[w])return true; else return false; } bool check(int x,int y){ if (x1[x]>=x1[y]&&y1[x]>=y1[y]&&x1[x]<x2[y]&&y1[x]<y2[y]||x2[x]<=x2[y]&&y2[x]<=y2[y]&&x2[x]>x1[y]&&y2[x]>y1[y]||x1[x]>=x1[y]&&y2[x]<=y2[y]&&x1[x]<x2[y]&&y2[x]>y1[y]||x2[x]<=x2[y]&&y1[x]>=y1[y]&&x2[x]>x1[y]&&y1[x]<y2[y]||x1[x]>=x1[y]&&x2[x]<=x2[y]&&y1[x]<=y2[y]&&y2[x]>=y1[y])return true; else return false; } int n; int ans ; void dfs(int dep,bitset<maxn> status){ ans = max(ans,(int)status.count()); if (dep==n+1)return; if (ans>=status.count()+n-dep+1)return; bitset<maxn> now1=status; bitset<maxn> now2 = status; dfs(dep+1,now2); if (status==(status&E[dep])){ now1.set(dep); dfs(dep+1,now1); } } int main(){ // freopen("input.in","r",stdin); while (scanf("%d",&n)!=EOF&&n){ for (int i=1;i<=n;i++){ E[i].reset(); } for (int i=1;i<=n;i++){ scanf("%d",x1+i); } for (int i=1;i<=n;i++){ scanf("%d",y1+i); } for (int i=1;i<=n;i++){ scanf("%d",x2+i); } for (int i=1;i<=n;i++){ scanf("%d",y2+i); } for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ if (i==j)continue; if (check(i,j))addEdge(i,j); } } ans=0; bitset<maxn> status; status.reset(); dfs(1,status); printf("%d\n",ans); } }
本套8道题全部pass的C++代码已挂到了我的GitHub(https://github.com/shiqitao/NowCoder-Solutions)
牛客网上的其他题目解答也在持续更新。
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <cstring>
using namespace std;
struct Rectangle
{
int x1, x2, y1, y2;
};
int main()
{
int n; cin >> n;
Rectangle *rect = new Rectangle[n];
int *x = new int[n * 2];
int *y = new int[n * 2];
for (int i = 0; i < n; i++) {
cin >> rect[i].x1;
x[i] = rect[i].x1;
}
for (int i = 0; i < n; i++) {
cin >> rect[i].y1;
y[i] = rect[i].y1;
}
for (int i = 0; i < n; i++) {
cin >> rect[i].x2;
x[i + n] = rect[i].x2;
}
for (int i = 0; i < n; i++) {
cin >> rect[i].y2;
y[i + n] = rect[i].y2;
}
sort(x, x + 2 * n);
sort(y, y + 2 * n);
vector<int> vectorx;
vector<int> vectory;
vectorx.push_back(x[0]);
vectory.push_back(y[0]);
for (int i = 1; i < 2 * n; i++) {
if (x[i] != x[i - 1]) {
vectorx.push_back(x[i]);
}
if (y[i] != y[i - 1]) {
vectory.push_back(y[i]);
}
}
delete[] x;
delete[] y;
unordered_map<int, int> myMapx;
unordered_map<int, int> myMapy;
for (int i = 0; i < vectorx.size(); i++) {
myMapx[vectorx[i]] = i;
}
for (int i = 0; i < vectory.size(); i++) {
myMapy[vectory[i]] = i;
}
int **map = new int*[vectorx.size()];
for (int i = 0; i < vectorx.size(); i++) {
map[i] = new int[vectory.size()];
memset(map[i], 0, sizeof(int)*vectory.size());
}
for (int i = 0; i < n; i++) {
for (int j = myMapx[rect[i].x1]; j < myMapx[rect[i].x2]; j++) {
for (int k = myMapy[rect[i].y1]; k < myMapy[rect[i].y2]; k++) {
map[j][k] += 1;
}
}
}
int maxNum = 0;
for (int i = 0; i < vectorx.size(); i++) {
for (int j = 0; j < vectory.size(); j++) {
maxNum = max(maxNum, map[i][j]);
}
}
for (int i = 0; i < vectorx.size(); i++) {
delete[] map[i];
}
delete[] map;
delete[] rect;
cout << maxNum;
return 0;
}