今天给大家说一下这道题,题意就不说了,主要说一下思路以及细节部分。
首先,从这道题来看就是求出车的坐标并且使得车之间不互相攻击且要满足车在规定的范围(矩形)之中,由于紫书说这道题考察了我们问题分解的能力,
所以我们从问题分解的角度来解决,对于问题分解,我们可以通过这种方法来简化问题,从而更好的解决,这道题而言,我们需要将横坐标与纵坐标分开,
乍一看横纵坐标怎么能分开呢?仔细想一想横纵坐标之间没有联系,所以可以分别从横、纵坐标入手来解决问题,这样我们将二维的图转化成了一维。
我们看看转换成一维后得到的结果,就是满足在区间内选择不重复的点,使得每个点都有对应的区间,类似于区间选点问题,所以我们要用贪心的方式来
找出解。我们在选择点时一定要满足不影响或者最小化影响后面的点的选择,这样如果都求不出来结果那么就输出IMPOSSIBLE了吧!我们怎么才能
最小化影响后面选点的情况呢?根据区间选点的思路,我们需要对每个区间的结尾x1、y1等以他们作为优先考虑的对象进行排序,为什么不能以x0、y0呢?
对于这个疑问我给出一个样例,然后大家想想就明白了。
样例如下:
3 1 1 3 3 1 1 3 3 2 2 2 2
大家想一想输出,然后看看自己的程序能不能输出正确的答案。
所以,我们确定了先按x1、y1从小到大排序,然后相同时按照x0、y0从大到小排序(想一想,为什么?),对横、纵坐标分别进行处理后我们合并输出答案就可以了。
下面是代码:
// UVa 11134 // 问题分解 /* 横与竖互不影响,所以将它们分开进行计算,这样我们将 二维转化成为了一维,然后成为了区间选点类似的问题,贪心法进行求解。 */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 5000 + 5; int X0[maxn], X1[maxn], Y0[maxn], Y1[maxn], rec[maxn], vis[maxn]; int r[maxn], c[maxn]; bool cmp1(int a, int b) { // 关于x的排序 if (X1[a] != X1[b]) return X1[a] < X1[b]; return X0[a] > X0[b]; } bool cmp2(int a, int b) { // 关于y的排序 if (Y1[a] != Y1[b]) return Y1[a] < Y1[b]; return Y0[a] > Y0[b]; } int main() { int n; while (scanf("%d", &n) == 1 && n) { for (int i = 0; i < n; ++i) rec[i] = i; for (int i = 0; i < n; ++i) scanf("%d%d%d%d", &X0[i], &Y0[i], &X1[i], &Y1[i]); bool ok = 1; sort(rec, rec+n, cmp1); memset(vis, 0, sizeof(vis)); int p = 0; while (p < n) { bool Vis = 0; for (int x = X0[rec[p]]; x <= X1[rec[p]]; ++x) if (!vis[x]) { vis[x] = Vis = 1; r[rec[p]] = x; break; } if (!Vis) ok = 0; p++; } sort(rec, rec+n, cmp2); memset(vis, 0, sizeof(vis)); p = 0; while (p < n) { bool Vis = 0; for (int y = Y0[rec[p]]; y <= Y1[rec[p]]; ++y) if (!vis[y]) { vis[y] = Vis = 1; c[rec[p]] = y; break; } if (!Vis) ok = 0; p++; } if (!ok) printf("IMPOSSIBLE\n"); else for (int i = 0; i < n; ++i) printf("%d %d\n", r[i], c[i]); } return 0; }
有不懂的地方请在下方留言,我会及时回答的。
原文地址:https://www.cnblogs.com/yifeiWa/p/11217592.html
时间: 2024-10-11 16:11:57