UVa #11134 Fabled Rooks (例题8-4)

来源:互联网 发布:色情网页站 源码 wap 编辑:程序博客网 时间:2024/06/04 18:56

书中的提示很有帮助,将这道题拆成两个一维空间分开进行判断,那么就变成了贪心法的区间重叠问题


设车的摆放位置为 [a,b]。我的算法是,将所有的区间按照 b 的值从小到大排列,b相同的按照 a 从小到大排列。然后从排好序的第一个区间(即a、b最小)开始选择摆放位置。


选摆放位置的时候,从左向右扫描,一旦有某一列暂时空着(没有其他的车摆在这一列),则马上摆放在这里,然后继续摆下一个车。如果某一辆车从左向右扫描到尽头,还没有找到空着的位置,那么此组数据无解


为什么这样的贪心法可以获得正确解:

因为区间已经按照a、b排好序,所以上下相邻的两个区间的左右边界一共有几种情况:

1、b1 < b2, a1 < a2

2、b1 < b2, a1 = a2

3、 b1 < b2, a1 > a2

4、 b1 = b2, a1 < a2

5、 b1 = b2, a1 = a1

(下面所说的最左端的点,全部指代从左侧开始往右搜索,第一个没有被其他车占着的点)

对于1和4,很显然第一个区间选择最左端的点是合理的,否则将会造成浪费(后面所有的区间都不再能选到那个点,那个点将永远空着)

对于2和5,如果第一个区间不选择最左端的点,那么第二个区间可以选择最左端的点,这和我们的解法结果相同。

对于3,第一个区间的选点对第二个区间并没有直接的影响,但是却可能会对第三个、第四个...造成影响(假如将第二个区间拿走,则第一个和第三个区间可能形成1、2、4、5的情况。如果第一个区间不选择最左端的点的话,可能会对第三个区间的选点会造成浪费)。

按照这样的算法,对于所有已经摆好的区间,我们可以确定整体上已经是最紧凑的状态,没有一点浪费。所以如果到了某一个区间,发现所有的位置都无法摆放,则可以果断返回无解,因为之前摆好的车再怎么调整也无法腾出空位。


要注意的是,同样的算法不可以按照 a 的大小来排序。


举一个反例:

两个区间a和b的范围分别是 [4,9] 和 [5,8]。按照排序规则,a要排在b上面:

(a)   4 5 6 7 8 9(b)     5 6 7 8


如果此时 1-7 都已经被其他的车占领,那么a区间会选择占据 8。区间b就会返回无解。但实际上a可以占9,而b占8


如果要按照a的大小排序的话,我感觉应该反向搜索,即每次摆放在最右端的可行位置。


不经意间居然做了一道带星号的例题。。我感觉也是撞大运了


Run Time: 0.026s

#define UVa  "LT8-4.11134.cpp"#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;struct Range {    int l, r, order;    Range(int a, int b, int c):l(a),r(b),order(c){}    bool operator < (const Range& r2) const {        return (r == r2.r) ? l < r2.l : r < r2.r;    }};//Global Variables.int n;const int maxn = 5000 + 10;vector<Range> restrict[2];int ans[maxn][2], vis[maxn][2];     //[0] for row, [1] for col;////void print_ans() {    for(int i = 0; i < n; i ++) {        if(vis[i][0] != -1) ans[vis[i][0]][0] = i;        if(vis[i][1] != -1) ans[vis[i][1]][1] = i;    }    for(int i = 0; i < n; i ++) {        printf("%d %d\n", ans[i][1]+1, ans[i][0]+1);    }}int solve() {    for(int k = 0; k < 2; k ++) {        for(int i = 0; i < n; i ++) {            int l, r, order;            l = restrict[k][i].l;            r = restrict[k][i].r;            order = restrict[k][i].order;            while(l <= r && vis[l][k] != -1) {                l++;            }            if(l > r) return 0;            vis[l][k] = order;        }    }    print_ans();    return 1;}int main() {    while(scanf("%d", &n) && n) {        restrict[0].clear();        restrict[1].clear();        memset(ans, -1, sizeof(ans));        memset(vis, -1, sizeof(vis));        int a, b, c, d;        for(int i = 0; i < n; i ++) {            scanf("%d%d%d%d", &a, &b, &c, &d);            Range colRange(a-1,c-1, i);                //ATTENTION. -1 applied.            Range rowRange(b-1,d-1, i);            restrict[0].push_back(rowRange);            restrict[1].push_back(colRange);        }        for(int i = 0; i < 2; i ++) sort(restrict[i].begin(), restrict[i].end());        if(!solve()) {            printf("IMPOSSIBLE\n");        }    }    return 0;}


0 0