POJ 1231The Alphabet Game【题解报告|思维】

题目链接
在这里插入图片描述
如果用直线划分空间的话,能不能做到每个区域里只有一种字母,或者没有字母


我们可以设置四个数组来 r [ ] , l [ ] , u [ ] , d [ ] r[], l[], u[], d[] r[],l[],u[],d[]来储存读入时覆盖没种数字的矩形的最右、左、上、下四个位置坐标。(可以认为 r [ ] r[] r[]储存的是对第i个数来说,其右侧直线的最右坐标值,因为这时如果直线比 r [ ] r[] r[]还靠右,那么这个数字必然无法分到同一个矩形里,另三个数组的意义同样)

然后慢慢更新这四组坐标,更新的依据是如果某个 r i ri ri在另一个 r j rj rj l j lj lj之间,那么如果要划分的话,至少是要在 r j rj rj处画直线,否则第 j j j个数就无法分到同一个矩形里,所以这时更新 r i = r j ri=rj ri=rj,同样的对 l , u , d l, u, d l,u,d做同样的更新。

        for(int i = 0; i < k; i++) {
            for(int j = 0; j < k; j++) {
                if(i == j) continue;
                if(r[i] > r[j] && r[i] < l[j]) r[i] = r[j];
                if(l[i] < l[j] && l[i] > r[j]) l[i] = l[j];
                if(u[i] > u[j] && u[i] < d[j]) u[i] = u[j];
                if(d[i] < d[j] && d[i] > u[j]) d[i] = d[j];
            }

那么在所有的数据都更新完之后,我们在进行一次check,看看是否还有某个 r i ( 或 l i ri(或li rili)在 r j 和 l j rj和lj rjlj之间同时 u i ( 或 d i ) ui(或di) uidi u j 和 d j uj和dj ujdj之间(就是某个矩形与另一个矩形有重合部分),如果有,那么进行划分时,必然会导致第i个数或者第j个数无法分到同一个矩形里。


bool check(int n) {
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            if(i == j) continue;
            if(((r[j] >= r[i] && r[j] <= l[i]) || (l[j] <= l[i] && l[j] >= r[i]))
                && ((u[j] >= u[i] && u[j] <= d[i]) || (d[j] <= d[i] && d[j] >= u[i])))
                    return 0;
        }
    }
    return 1;
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <numeric>
 
using namespace std;
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define INF 1000000000
 
int r[27], l[27], u[27], d[27];
 
bool check(int n) {
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            if(i == j) continue;
            if(((r[j] >= r[i] && r[j] <= l[i]) || (l[j] <= l[i] && l[j] >= r[i]))
                && ((u[j] >= u[i] && u[j] <= d[i]) || (d[j] <= d[i] && d[j] >= u[i])))
                    return 0;
        }
    }
    return 1;
}
 
int main() {
    int t, k ,p;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &k, &p);
        for(int i = 0; i < k; i++) {
            int rr = INF, ll = 0, uu = INF, dd = 0,tmp, tmpp;
            for(int j = 0; j < p; j++) {
                scanf("%d%d", &tmp, &tmpp);
                rr = min(rr, tmp), ll = max(ll, tmp), uu = min(uu, tmpp), dd = max(dd, tmpp);
            }
            r[i] = rr, l[i] = ll, u[i] = uu, d[i] = dd;
        }
        for(int i = 0; i < k; i++) {
            for(int j = 0; j < k; j++) {
                if(i == j) continue;
                if(r[i] > r[j] && r[i] < l[j]) r[i] = r[j];
                if(l[i] < l[j] && l[i] > r[j]) l[i] = l[j];
                if(u[i] > u[j] && u[i] < d[j]) u[i] = u[j];
                if(d[i] < d[j] && d[i] > u[j]) d[i] = d[j];
            }
        }
        if(check(k)) puts("YES");
        else puts("NO");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值