最近做题目感觉贪心题很容易卡壳,就多练练开阔开阔思路吧.
这题开始比较不好想,一个二维的问题很难下手,看了紫书上面说分割成两个一维的问题会简单很多.就稍微有了点思路.和大家分享一下
行和列显然是无关的,因为如果行可以摆,列也可以摆,那么摆到对应的row,col上面就可以了.否则就无解.这是分割的可行性.
那么如何贪心呢?可以这么考虑,每个棋子摆放的区间[l,r].而每一个格子都需要一个棋子,如果在左端点相同的情况下,显然左端点上要放的棋子应该是右边界更小的那一个.这是基本的贪心思想,不过还需要在放完后对当前所有相同左端点的区间做处理.
比如有三个棋子,区间范围为[1,1],[1,2],[1,3],在第一次贪心时候,选的是第一个区间,之后,因为1这个位置已经有棋子了,那么后面两个区间要进行更改,变成[2,2],[2,3].第二次贪心的时候也是一样的处理,但如果说在某个时候,当前需要的格子没有任何一个棋子左边界可以满足.或者修改区间的时候左边界和右边界相等,也就是不能直接或者间接的出现一个区间的l == r(修改之前).就直接return false.
可能有更优秀的解法,这里只是提供一个参考.
这题的思想还是很重要的,分割问题,贪心方法的处理都有启发性.
附上AC代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
const int max_n = 1e4 + 10;
int n;
struct line {
int s, e, num;
friend bool operator <(line a, line b) {
if (a.s == b.s) return a.e > b.e;
else return a.s > b.s;
}
};
line row[max_n];
line col[max_n];
bool vis[max_n];
int ans[max_n][2];
int judge(line* a, int pos) {
priority_queue<line> q;
for (int i = 1; i <= n; ++i) q.push(a[i]);
int curpos = 1;
while (!q.empty()) {
line cur = q.top();
q.pop();
if (curpos != cur.s) return 0;
while (!q.empty() && curpos == q.top().s) {
line y = q.top();
q.pop();
if (y.e == curpos) return 0;
y.s++;
q.push(y);
}
ans[cur.num][pos] = curpos;
curpos++;
}
return 1;
}
int main() {
// freopen("as.txt","r",stdin);
while (cin >> n && n) {
for (int i = 1; i <= n; ++i) {
scanf("%d%d%d%d", &row[i].s, &col[i].s, &row[i].e, &col[i].e);
row[i].num = i;
col[i].num = i;
}
if (judge(row, 0) && judge(col, 1)) {
for (int i = 1; i <= n; ++i) {
cout << ans[i][0] << " " << ans[i][1] << endl;
}
}
else cout << "IMPOSSIBLE\n";
}
return 0;
}```