2019牛客暑期多校训练营(第五场)——I(听说很暴力)

问题虫洞:three points 1

 

黑洞内窥:

t组样例,每组样例输入w, h, a, b, c,五个数字且都不大于50.

意为在坐标系中,0 <= x <= w,  0<=y<=h,求出三个点X, Y, Z, 并且|XY| = a, |XZ| = b, |YZ| = c,

求这三点坐标并依次输出。

 

思维光年:

一开始不太正确的做法:

找出最长的边c (假设这里是c)靠在x轴上,一端点在(0, 0), 然后求另一端点

如果c>x,则该边向上旋转,直到接触到wh这个矩阵的边,然后设该点为第二个端点。

之后你知道了两个点,三条边,你就可以用余弦定理和勾股定理求出第三个点,

那么问题就是你要放哪一条边更靠近y轴呢?!(或者说是挑哪一条边的端点连接零点(0,0))

相信绝大多数人和我一样放了第二大的边b(设b为第二大的边)

然后,这样的话,~~问题就解决了!!  恭喜你可以wa到死了。。。

 

其实咋的一想,我们都范了想当然的错误,为什么呢?!

因为有的时候你需要放小边连接零点,而放中边则会导致另一端点超出wh的范围。。。。

(有人反应BZ偷懒不画图,,,,哭唧唧~~~~再也不用word画图了)

(这个图还是比较清秀的,,,,看到了吧,,,,,)

所以,其实我们把小边和中边各跑一遍,应该可以过,(应该可以,没敲过。。)

 

真正的做法:

所以,不如干脆写成函数,暴力abc的每个排序,符合就输出,(而题目给出总有符合的)否则就继续找。。。

还有就是,用反函数,不要用联立余弦勾股的方程组求解(wa到怀疑人生),即便你可以二分区间找到答案。。。

对了,最后就精度问题出题人也不忘卡你一下,,,所以,,,你也要卡一下至少1e-6的精度范围。

ACcode:

//#include<bits/stdc++.h>
//std::ios::sync_with_stdio(false);
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <set>
#include      <map>
#include    <queue>
#include    <stack>
#include   <string>
#include   <math.h>
#include   <vector>
#include  <cstring>
#include <stdlib.h>
#include <string.h>
using namespace std;
typedef long long ll;
#define MAXN 3005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
//const ll mod = 9901;
#define mem(a, b) memset(a, b, sizeof(a))
ll mod;

double w, h;
struct node
{
    double x, y;
} stu[3];

int solution(double a, double b, double c, int x, int y, int z)
{
    stu[x].x = 0.0;
    stu[x].y = 0.0;
    if(a <= w)
    {
        stu[y].x = a;
        stu[y].y = 0.0;
    }
    else
    {
        stu[y].x = w;
        stu[y].y = sqrt(a*a - w*w);
    }
    double d = acos((a*a+b*b-c*c)*1.0/(2*a*b));//这里用反函数求角度
    d+=atan(stu[y].y*1.0 / stu[y].x);

    stu[z].x = b*cos(d);                       //知道角度用三角函数直接得出最后一点的坐标
    stu[z].y = b*sin(d);

    if(stu[z].x >= 0-1e-8 && stu[z].x <= w+1e-8 && stu[z].y>=0-1e-8 && stu[z].y <= h+1e-8)
    //注意精度,不然会wa。
    {
        printf("%.12f %.12f ", stu[0].x, stu[0].y);
        printf("%.12f %.12f ", stu[1].x, stu[1].y);
        printf("%.12f %.12f\n", stu[2].x, stu[2].y);
        return 1;
    }
    return 0;
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        double a, b, c;
        scanf("%lf %lf %lf %lf %lf", &w, &h, &a, &b, &c);
        if(solution(a, b, c, 0, 1, 2)) continue;    //搜每一种情况
        if(solution(a, c, b, 1, 0, 2)) continue;
        if(solution(b, a, c, 0, 2, 1)) continue;
        if(solution(b, c, a, 2, 0, 1)) continue;
        if(solution(c, a, b, 1, 2, 0)) continue;
        if(solution(c, b, a, 2, 1, 0)) continue;
    }
    return 0;
}

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值