[贪心] UVa11134 Fabled Rooks 传说中的车 (问题分解思想运用的典例)

题目

在一个n*n(1<=n<=5000)的棋盘上放置n个车,每个车都只能在给定的一个矩形里放置,使其n个车两两不在同一行和同一列,判断并给出解决方案。

思路

1.问题分解:由于本题中,一个车的x坐标和y坐标没有关系,所以可以分解处理。所以问题分解的基本方法就是:将问题分解成独立的不相关的小问题进行解决。本题 O ( n 2 ) -> O ( n )
2.问题抽象:拿x坐标为例,有n个坐标区间,有n个点要放到1~n上。也就是,用尽量多的点覆盖区间,即LRJ的“逆’区间选点’”问题。
3.贪心策略:是区间都为[ a i , b i ]。将区间们按 b i 的大小升序排序, b i 相同时 a i 升序。依次遍历每个区间,遍历到时,从区间的最左边尝试放点。若直到最右边都没放下,宣布无解。
4.贪心证明:点放一个排序好的区间们里面的一个区间的,越往左越对后面区间影响小。
5.不能用 a i 升序排列,比如如下这种情况就会卡:
3
1 1 3 3
1 1 3 3
2 2 2 2

代码

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;

const int maxn = 5000 + 1000;
struct qujian {
    int x, y, k;
    bool operator < (const struct qujian& rhs) const {
        return y < rhs.y;
    }
}AX[maxn], AY[maxn];
int n;
pair<int, int> ans[maxn];
bool GX[maxn], GY[maxn], fail;

void solveX(int x) {
    if (x < n) {
        int p = AX[x].x;
        while (GX[p]) {
            if (p == AX[x].y) {
                fail = true;
                return;
            }
            p++;
        }
        GX[p] = true;
        ans[AX[x].k].first = p;
        solveX(x + 1);
    }
}

void solveY(int x) {
    if (x < n) {
        int p = AY[x].x;
        while (GY[p]) {
            if (p == AY[x].y) {
                fail = true;
                return;
            }
            p++;
        }
        GY[p] = true;
        ans[AY[x].k].second = p;
        solveY(x + 1);
    }
}

void print() {
    if (fail)
        printf("IMPOSSIBLE\n");
    else {
        for (int i = 0; i < n; i++)
            printf("%d %d\n", ans[i].first, ans[i].second);
    }
}

int main() {
    while (scanf("%d", &n) == 1 && n) {
        for (int i = 0; i < n; i++) {
            scanf("%d%d%d%d", &AX[i].x, &AY[i].x, &AX[i].y, &AY[i].y);
            AX[i].k = AY[i].k = i;
        }
        fail = false;
        memset(GX, 0, sizeof(GX));
        memset(GY, 0, sizeof(GY));
        sort(AX, AX + n);
        sort(AY, AY + n);
        solveX(0);
        solveY(0);
        print();
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80575558