题意
一些人在一个矩形的房间里,每个人有一个坐标,和一个方向,视角的宽度是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;
}