[AIZU1359] Wall Clocks [2015 ACM-ICPC Asia Tsukuba Regional Contest D]

题意

一些人在一个矩形的房间里,每个人有一个坐标,和一个方向,视角的宽度是90度,于是每个人都会看到墙壁的一部分。现在要求在墙壁上挂最少的时钟使得每个人至少可以看到一个时钟。

题解

以每个人左侧视线(或右侧)与墙的交点为关键字排序,再枚举从每个人开始将墙壁断开,形成一条直线,直线上有一些线段,要求放置一些点,使得每条线段至少包含一个点。
此时可以进行贪心,以线段左端点位置为第一关键字,右端点为第二关键字,从左向右进行压栈,直到必须放置第二个点时弹栈。

代码

比赛时没打模板
具体操作时要找到从一个点出发,射向某个方向的射线和矩形边框的交点,射线方向分四种,每一种有两种相交情况。

#include <bits/stdc++.h>

using namespace std;

#define  maxn  1010LL

#define  up(x)    (x)
#define  right(x) (w+d-(x))
#define  down(x)  (w+d+w-(x))
#define  left(x)  ((w+d+w+(x))%(w+d+w+d))

struct seg {
    int l,r;
    bool operator < (const seg&b) const {
        if (l == b.l) return r < b.r ;
        return l < b.l;
    }
} s[maxn] ;

int d , w , x , y , n;

int leftup(int x,int y) {
    if (x > d-y) return up(x-d+y);
    else return left(x+y);
}

int rightup(int x,int y) {
    if (w-x > d-y) return up(x+d-y) ;
    else return right(y+w-x) ;
}

int leftdown(int x,int y) {
    if (x > y) return down(x-y) ;
    else return left(y-x) ;
}

int rightdown(int x,int y) {
    if (w-x > y) return down(x+y);
    else return right(y-w+x) ;
}

int sta[maxn],top;

int main() {
int dir,ANS,ans,nowright;
    scanf("%d%d%d", &n, &w, &d);
    for (int i = 1 ; i <= n ; i ++ ) {
        scanf("%d%d", &x, &y);
        while (dir=getchar(),dir==' ');
        if (dir == 'N') {
            s[i].l = leftup(x,y) ;
            s[i].r = rightup(x,y) ;
        }
        if (dir == 'E') {
            s[i].l = rightup(x,y) ;
            s[i].r = rightdown(x,y) ;
        }
        if (dir == 'S') {
            s[i].l = rightdown(x,y) ;
            s[i].r = leftdown(x,y) ;
        }
        if (dir == 'W') {
            s[i].l = leftdown(x,y) ;
            s[i].r = leftup(x,y) ;
        }
        if (s[i].r < s[i].l) s[i].r += w+w+d+d ;
  //  printf("i = %d, l = %d , r = %d\n",i,s[i].l,s[i].r);
    }
    sort(s+1,s+n+1);
    ANS = n ;
    for (int i = 1 , j , len ; i <= n ; i ++ ) {
        ans = 0;
        sta[top=1] = i ;
        nowright = s[i].r;
        len = 1 ;
        j = i ;
        while (++len <= n) {
            j = j % n + 1 ;
            if (s[j].l > nowright) {
                ans ++ ;
                top = 0 ;
                sta[++top] = j ;
                nowright = s[j].r ;
            } else {
                sta[++top] = j ;
                if (s[j].r < nowright) nowright = s[j].r ;
            }
        }
        ans ++ ;
        if (ans < ANS) ANS = ans ;
        s[i].l += w+w+d+d ;
        s[i].r += w+w+d+d ;
    }
    printf("%d\n", ANS) ;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值