poj 2540

题目概述

一个房间,左下角坐标(0,0),右上角坐标(10,10),A把某物藏于某处,B从(0,0)出发,每次走到一个位置,A会说距离藏物点更近了(Hotter),更远了(Colder)或距离没变(Same),给定每次B到的位置(x,y)和A喊的话,求可能藏物的区域的面积
A每次只会说Hotter,Colder或Same

时限

1000ms/3000ms

输入

每行两个浮点数x,y,代表B到的位置,以及一个字符串,代表A说的话,输入到EOF为止

限制

输入最多包含50行

输出

每行一个保留两位小数的浮点数,为所求可行域的面积

样例输入

10.0 10.0 Colder
10.0 0.0 Hotter
0.0 0.0 Colder
10.0 10.0 Hotter

样例输出

50.00
37.50
12.50
0.00

讨论

计算几何,半平面交,不知是题水还是额变得谨慎了,竟然一发拿下,有点受宠若惊
首先要明白题意,每次移动后,现在的和上次的两个点连成一条线段,其中垂线构成半平面,因为中垂线上的点和移动前后的位置距离都相等,由喊的话决定可行域的方向,初始的可行域是整个房间,每次移动,进行一次切割,并求出其面积,就是这样
接下来是实现部分,这次表示半平面的方式比上一次poj 1755还要麻烦一点,没有线上的点,没有任何参数,借用向量式的思想(记得蓝白数上用的就是向量式),找到半平面上一个点及其方向向量,点用中点就行,求方向向量时,先以坐标表示出移动前后两点的方向向量,(x2-x1,y2-y1),然后交换逗号左右二者,并将其中一个取相反数,得到的一种形式是(y2-y1,x1-x2),然后将其与中点做和,得到半平面上第二个点,两点式,额很熟悉,接下来确定喊话的意义,其实画个图就能看出来,在上面得到的形式下,Hotter是左侧,Colder是右侧,Same比较特殊,另谈,确定左右后就可以根据每次的位置,喊话内容计算半平面交了,当出现Same或后面喊的话与前面矛盾的时候,什么也不用做,之后可行域会被更新为空,往后面积就全是0了,求面积时需要注意一点,虽然对任何简单多边形利用向量积都能算出面积,不过那是有向面积,由于最后点集里点的顺序不确定,因而输出时需要带绝对值
精度沿用的上一题(poj 1755)的,忘了改了

题解状态

196K,0MS,C++,2115B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 300
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-16

struct Pt//点的结构
{
    double x, y;
    Pt() {}
    Pt(double x, double y) :x(x), y(y) {}//方便初始化前四个点写的构造函数
}pt1[MAXN] = { Pt(0,0),Pt(10,0),Pt(10,10),Pt(0,10) }, pt2[MAXN];//两个半平面交辅助数组(点集) 事先以房间边界初始化
int hpt1, hpt2;//两个点集中点的数量
int signal(double a)//符号函数 EPS小的话应该会有不少漏网之鱼 可见数据之弱
{
    if (abs(a) < EPS)
        return 0;
    return a > 0 ? 1 : -1;
}
double xp(Pt &a, Pt &b, Pt &c)//熟悉的向量积 现在普遍青睐三个点的形式而不是六个double
{
    return (a.x - b.x)*(c.y - b.y) - (a.y - b.y)*(c.x - b.x);
}
Pt point_of_intersection(Pt &a, Pt &b, Pt &c, Pt &d)//求交点 无论是两点一式 两线 四点 八double 核心部分都是一样的
{
    double Sabc = xp(c, a, b), Sabd = xp(d, a, b);
    return Pt((Sabc*d.x - Sabd*c.x) / (Sabc - Sabd), (Sabc*d.y - Sabd*c.y) / (Sabc - Sabd));//仍然是定比分点公式
}
void fun()
{
    double x1 = 0, y1 = 0, x2, y2;//上一次的位置 这一次的位置
    char str[10];//存放喊话的字符串
    hpt1 = 4;//一开始点集1有4个点 房间边界
    while (~scanf("%lf%lf%s", &x2, &y2, str)) {//input
        Pt p1((x1 + x2) / 2, (y1 + y2) / 2), p2(y2 - y1 + (x1 + x2) / 2, x1 - x2 + (y1 + y2) / 2);//根据前后两点揪出半平面上的两个点 表示半平面
        hpt2 = 0;//点集2初始为0
        for (int p = 0; p < hpt1; p++) {//下面分情况进行半平面交
            if (str[0] == 'H') {//热了取左侧
                if (signal(xp(pt1[p], p1, p2)) <= 0)
                    pt2[hpt2++] = pt1[p];
                else {
                    if (signal(xp(pt1[(p - 1 + hpt1) % hpt1], p1, p2)) < 0)
                        pt2[hpt2++] = point_of_intersection(pt1[p], pt1[(p - 1 + hpt1) % hpt1], p1, p2);
                    if (signal(xp(pt1[(p + 1) % hpt1], p1, p2)) < 0)
                        pt2[hpt2++] = point_of_intersection(pt1[p], pt1[(p + 1) % hpt1], p1, p2);
                }
            }
            else if (str[0] == 'C') {//冷了取右侧
                if (signal(xp(pt1[p], p1, p2)) >= 0)
                    pt2[hpt2++] = pt1[p];
                else {
                    if (signal(xp(pt1[(p - 1 + hpt1) % hpt1], p1, p2)) > 0)
                        pt2[hpt2++] = point_of_intersection(pt1[p], pt1[(p - 1 + hpt1) % hpt1], p1, p2);
                    if (signal(xp(pt1[(p + 1) % hpt1], p1, p2)) > 0)
                        pt2[hpt2++] = point_of_intersection(pt1[p], pt1[(p + 1) % hpt1], p1, p2);
                }
            }
        }//Same的情况什么也不用做 由于点集2没有点 自然会返回0面积
        for (int p = 0; p < hpt2; p++)
            pt1[p] = pt2[p];
        hpt1 = hpt2;
        double area = 0;
        for (int p = 0; p < hpt1 - 1; p++)
            area += xp(pt1[p], pt1[0], pt1[(p + 1) % hpt1]);
        printf("%.2lf\n", abs(area / 2));//output//注意面积需要取绝对值
        x1 = x2, y1 = y2;//更新移动点
    }
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    fun();//有史以来最短的main函数 其中两行还是注释
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值