题目描述:
给出n个人的图像,有高和宽,图像可以横着也可以竖着,对于两张图像 w i , h i w_i,h_i wi,hi 和 w j , h j w_j, h_j wj,hj,如果i能在j前面,当且仅当满足下面两个条件之一:(1) w i < w j w_i<w_j wi<wj且 h i < h j h_i<h_j hi<hj;(2) h i < w j h_i<w_j hi<wj且 w i < h j w_i<h_j wi<hj,对于每张图像,问是否能找到一张图像在它前面,若能,输出下标,若不能输出-1。
题解:
错误想法:
一开始我认为找一个高和宽最小的图像m(当高和宽都更小时更新最小值),然后让每张图像x与m进行比较确定是否可以有一张图像在x前面,反例是,如果一个图像r,它的高很大而宽极小,它本来可以在另一张图像y(高更大,宽比r大)前面,但是因为r的高很大,导致m不能进行更新,而可能m的宽比y大,导致m不能在y前面,而实际上r可以在y的前面。
正解:
由题目描述的比较方式我们可知,高和宽其实不用区分,所以我们让小的为高,大的为宽,然后以其中一种标准来排序,例如按高由小到大到达排序,这样对于每一张图像,只需判断当前图像的宽是否大于一个维护值,这个维护值是比当前图像高度小的图像的最小的宽。对于高度的处理,我们只需要将同一高度的图像放在一起处理,方法是利用两点法确定高度相同的图像的下标范围,那么前面的图像的高度一定就小于当前这些图像的高度,也就只需要判断宽度就可以了,在处理完同等高度的图像后,还要利用这些图像去更新最小宽度,以供下次要处理的那些图像(高度更高)使用。
C++技巧
- iota,头文件是numeric,可以实现一个递增的赋值,例如:iota(p.begin(), p.end(), 0);,可以将p的每个元素赋值为0,1,2,…
- 如果要保存排序后每一个元素原来的位置,可以使用结构体,但是也可以使用一个数组p,来保存元素排序后的位置,即数组p的下标 i 为元素原来的位置,p[i]为排序后的位置。
AC Codes:
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <numeric>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 2e5 + 6, M = 1e9 + 7, INF = 0x3f3f3f3f;
int main() {
//freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> h(n), w(n);
for (int i = 0; i < n; i++) {
cin >> h[i] >> w[i];
if (h[i] > w[i]) {
swap(h[i], w[i]);
}
}
vector<int> p(n);
iota(p.begin(), p.end(), 0);
sort(p.begin(), p.end(), [&](int i, int j) {
return h[i] < h[j];
});
vector<int> ans(n, -1);
int u = -1;
for (int i = 0; i < n; ) {
int j = i;
while (j < n && h[p[i]] == h[p[j]]) {
j++;
}
for (int k = i; k < j; k++) {
if (u != -1 && w[u] < w[p[k]]) {
ans[p[k]] = u;
}
}
for (int k = i; k < j; k++) {
if (u == -1 || w[u] > w[p[k]]) {
u = p[k];
}
}
i = j;
}
for (int i = 0; i < n; i++) {
cout << ans[i] + (ans[i] >= 0) << " \n"[i == n - 1];
}
}
return 0;
}