UVA 11134 Fabled Rooks 【贪心+问题分解】

题目链接:https://cn.vjudge.net/problem/UVA-11134

题意:

在一个n*n的棋盘中放置 n个棋子,每个棋子有固定的放置范围,在满足放置范围的情况下,放置的棋子横向和纵向不能有第二个棋子;输出棋子的放置位置或者 impossible;

思路:

解这题的关键就是问题的分解,如果能想到问题的分解方法的话,就比较容易做了;因为之前也做过类似这种方格的题目,想到的方法就是分解成几个小方块,看看能不能把小问题的答案合并成大问题的答案,显然这种思路是错误的,因为有很多需要分开讨论的情况;如果你在分析一个问题的时候,有多种情况需要分开讨论求解的话,一般这种思路都不是最好的,或者说是错误的;平时做题的时候一定积累一些判断思路对错的经验,不然在时间上会很吃亏,发现思路错了就再重新想一个,而不是去想怎么解决各自各样的复杂情况;

问题的分解:

题目要求横向和纵向不能有第二个棋子;那么n*n的棋盘中放n个棋子,也就意味着横坐标每个点都只有一个棋子,同样的纵坐标也是;那么我可以优先处理横向放置方法,然后再处理纵向的放置方法;如果横向能够满足放置的条件,然后去处理纵向的;这样分解的好处是什么?我们在不分解问题之前,肯定有很多人在模拟放棋子的时候是同时考虑横向和纵向的,比如说我放一颗棋子,我先考虑在棋子的放置范围内,横向有没有其他的棋子,然后再看看纵向有没有其他棋子,这样的模拟方法写起代码来及其麻烦,而且还有后效性;这也是我之前想的,把大方块分成小方块的方法不可行的原因(没有解决主要矛盾);既然同时考虑会很麻烦,那分开考虑是否可行?

贪心:

横向放置和纵向放置都是用贪心实现的(这里只说横向就行了);(我在之前的博客也讲过,因为贪心大多都是根据排序方案优先处理某些数据实现的,如果要去检查自己的贪心策略是否可行,一定要从排序方案开始检查,检查的方法就是考虑排序的过程中,两者判断条件相同的情况下,是否取任意一个都不会影响最终结果,如果会的话,就要考虑如何修改排序方案了)

///////// 下面这两段的内容是写给自己看的,可以直接跳过;

先说说第一个 WA的贪心策略: 根据横向的放置范围的左值从小到大排序,如果左值大小相等再根据右值从小到大排序;咋一看好像可行,但是如果一个放置范围小的棋子的左值比一个范围大的左值大,那么那个范围大的会优先处理;导致的情况可能是,范围大的棋子放完后,范围小的就没棋子可以放了,然而范围大的虽然放完,但是能放的区域还有很多,如果优先放范围小的,然后再放范围大的就有可能同时满足两个棋子的放置,显然这种贪心并不正确;

第二个WA的贪心策略: 既然上一个策略因为范围的问题而导致错误,那么就考虑范围的排序;优先放置范围小的棋子,然后再考虑范围大的,这才有可能容纳更多的棋子;然后检查一下,如果范围相同的情况下,是否取任意一个数据优先处理都是正确的?我们看看这 3个数据  1 2 |  2 3 | 1 2  ,这三个数据的范围是相同的,如果我们根据给出的顺序处理,那么 第1 我们会优先 看看1能不能放,可以就标记一下,然后看第二个  2是否能放,是就标记一下,然后再看第三个,显然没位置可以放了,但是如果我们让第二个棋子放在 3这个位置,第三个就能放棋子了;这里的检查方法也是我上面说的那个,一定要考虑,如果排序条件相同,一定要保证取任意一个都不影响正确答案;

根据第二个策略;想想错误的原因:第二个棋子虽然 2和3都能放,但是,2却是第三个棋子的右界,第二个棋子的右界比第三个的要大,说明第二个棋子还有后移一位放置棋子的可能;

//////////  上面内容可跳过

总结上面的错误,正确的贪心策略就是根据棋子的右界从小到大排序;

下面是代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<sstream>
#include<vector>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(0);

typedef long long ll;
const int Maxn = 5100;
const long long LINF = 1e18;
const int INF = 0x3f3f3f3f;

struct point {
    int hx,hy,tx,ty,xx,yy,pos;
} a[Maxn];

int vis[Maxn];

bool hang (const point &a1, const point &a2) {
    return a1.ty < a2.ty;
}

bool lie (const point &a1, const point &a2) {
    return a1.tx < a2.tx;
}

bool cmp (const point &a1, const point &a2) {
    return a1.pos < a2.pos;
}

int main (void)
{
    int n;
    while (scanf("%d",&n) != EOF) {
        if(!n) break;
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d%d%d",&a[i].hx,&a[i].hy,&a[i].tx,&a[i].ty);
            a[i].pos = i;
        }
        sort(a+1,a+n+1,hang);
        memset(vis,0,sizeof(vis));
        bool flag;
        for (int i = 1; i <= n; ++i) {
                flag = false;
            for (int j = a[i].hy; j <= a[i].ty; ++j) {
                if(!vis[j]) {
                    a[i].yy = j;
                    flag = true; vis[j] = 1;
                    break;
                }
            }
            if(!flag) {
                printf("IMPOSSIBLE\n"); break;
            }
        }
        if(!flag) continue;
        sort(a+1,a+n+1,lie);
        memset(vis,0,sizeof(vis));
        for (int i = 1; i <= n; ++i) {
            flag = false;
            for (int j = a[i].hx; j <= a[i].tx; ++j) {
                if(!vis[j]) {
                    a[i].xx = j;
                    flag = true; vis[j] = 1;
                    break;
                }
            }
            if(!flag) {
                printf("IMPOSSIBLE\n"); break;
            }
        }
        if(!flag) continue;
        sort(a+1,a+n+1,cmp);
        for (int i = 1; i <= n; ++i) {
            printf("%d %d\n",a[i].xx,a[i].yy);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/81739063