UVa10084 - Hotter Colder(半平面交【难码)

本文介绍了一种基于玩家猜测反馈的游戏寻宝算法实现。通过分析玩家每次猜测与真实位置的距离变化,利用几何原理缩小搜索范围,最终确定可能的藏宝区域。文章详细解释了算法流程,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

分析:
这是一个游戏,游戏规则是这样的:
甲闭上眼睛,乙在一个多边形的屋子里藏一个物品
睁开眼睛后,甲可以猜这个物体在哪里。第一次必须猜(0,0),之后每猜一次,乙根据这个位置和上一个位置哪里离正确位置近作出回答
如果新猜的点比较近,回答“Hotter”
如果之前的点比较近,回答“Colder”
如果二者相同,回答“Same”
求所有可能位置占得面积

分析:
实际上,每一次乙回答,就把整个平面分成了两部分
界限是两点之间连线的垂直平分线
所以最后的答案就是多边形和这n个半平面的交

代码超级麻烦,真算得上可以光速弃疗了
独立码到一半,深度崩溃,于是找到一个AC代码对着码了一遍

//这里写代码片
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>

using namespace std;

const double eps=1e-6;

struct node{
    double x,y;
    node (double xx=0,double yy=0)
    {
        x=xx;y=yy;
    }

};

vector <node> p;

struct line{
    double a,b,c;
    line (double aa=0,double bb=0,double cc=0)
    {
        a=aa;b=bb;c=cc;
    }
    node setline(node x,node y)              //求直线表达式 
    {
        a=x.y-y.y;
        b=y.x-x.x;
        c=x.x*y.y-x.y*y.x;
    }
    node getcross(line l)                    //求交点 
    {
        node t;
        t.x=(l.b*c-b*l.c)/(l.a*b-l.b*a);
        t.y=(l.c*a-c*l.a)/(l.a*b-l.b*a);
        return t;
    }
};

node operator + (const node &a,const node &b){return node(a.x+b.x,a.y+b.y);}
node operator - (const node &a,const node &b){return node(a.x-b.x,a.y-b.y);}
node operator * (const node &a,const double &b){return node(a.x*b,a.y*b);}
node operator / (const node &a,const double &b){return node(a.x/b,a.y/b);}
bool operator < (const node &a,const node &b){return a.y<b.y||(a.y==b.y && a.x<b.x);}       //注意这个重载 
bool operator == (const node &a,const node &b){return a.x==b.x && a.y==b.y;}

double Cross(node x,node y){return x.x*y.y-x.y*y.x;}
double Dot(node x,node y){return x.x*y.x+x.y*y.y;}
double dis(node x,node y){return sqrt(Dot(x-y,x-y));}

int dcmp(double x)
{
    if (fabs(x)<eps) return 0;
    else if (x>0) return 1;
    else return -1; 
}

line getline(node x,node y)              //求垂直平分线 
{
    line t;
    t.a=y.x-x.x;
    t.b=y.y-x.y;
    t.c=(x.x*x.x-y.x*y.x+x.y*x.y-y.y*y.y)/2;
    return t;
}

bool cmp(node a,node b)
{
    if (fabs(Cross(a-p[0],b-p[0]))<eps) return dis(a,p[0])<dis(b,p[0]);
    else return Cross(a-p[0],b-p[0])>0;
}

void init()
{
    p.clear();
    p.push_back(node(0,0));
    p.push_back(node(10,0));
    p.push_back(node(10,10));
    p.push_back(node(0,10));
}

void doit(node pre,node d,int ff)
{
    line l2=getline(pre,d); 
    vector <node> v;
    for (int i=0;i<p.size();i++)
    {
        if (ff<0) 
        {
            if (dis(p[i],pre)<dis(p[i],d))       //Colder 
                v.push_back(p[i]);
        }
        else
        {
            if (dis(p[i],pre)>dis(p[i],d))       //Hotter
                v.push_back(p[i]);
        }
    }
    p.push_back(p[0]);
    for (int i=1;i<p.size();i++)
    {
        line l1;
        l1.setline(p[i-1],p[i]);
        if (fabs(l1.a*l2.b-l1.b*l2.a)<eps) continue;
        node tmp=l2.getcross(l1);
        if (fabs( fabs(tmp.x-p[i-1].x)+fabs(tmp.x-p[i].x)-fabs(p[i].x-p[i-1].x) ) > eps) continue;
        if (fabs( fabs(tmp.y-p[i-1].y)+fabs(tmp.y-p[i].y)-fabs(p[i].y-p[i-1].y) ) > eps) continue;
        v.push_back(tmp);
    }
    p.clear();
    sort(v.begin(),v.end());
    for (int i=0;i<v.size();i++)
    {
        if (p.size()>0 && ( fabs(p.back().x-v[i].x)<eps && fabs(p.back().y-v[i].y)<eps )) continue;
           p.push_back(v[i]);
    }
    if (p.size()>=1) sort(++p.begin(),p.end(),cmp);
}

double SS()
{
    double ans=0;
    for (int i=1;i<p.size()-1;i++)
        ans+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return fabs(ans)/2;
}

int main()
{
    init();

    char s[20];
    node pre(0,0),d;
    double area=SS();

    while (cin>>d.x>>d.y>>s)
    {
        if (s[0]=='C')
        {
            if (fabs(d.x-pre.x)>eps || fabs(d.y-pre.y)>eps)
            {
                doit(pre,d,-1);
                area=SS();
            }
        }
        else if (s[0]=='H')
        {
            if (fabs(d.x-pre.x)>eps || fabs(d.y-pre.y)>eps)
            {
                doit(pre,d,1);
                area=SS();
            }
        }
        else
        {
            area=0;
        }
        printf("%.2lf\n",area);
        if (area<eps) break;
        pre=d;
    }

    while (cin>>d.x>>d.y>>s) printf("0.00\n");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值