【思维 && 几何】Gym - 101063K Dire, Dire Docks

Problem Description

给你n个点,分别给出它们的坐标。问你能否连接n条边,使的其成为连通图。最多四条河流在任何一个码头相遇,河流除了在码头外,不能相碰。输出n条你所建立的河流
例:
5
-1 0
2 3
3 2
5 4
6 1
输出:
3 2
3 4
5 3
1 5
2 4

思路:

就是一个思维题,看你如何建立河流,能满足要求。
其中一种方法就是,我AC的方法。把点按从小到大排序,从最左边的点,开始往右边的点连接,可以做到连接n-1条边,不会有交叉,这时候最后一条边是最左边的点到距离该点斜率最高或者最低的点。这样就连接出n条边了
只要是斜率问题,就得想到乘法,又白白wa了好几发。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e3+100;
const double inf = 1.0*0x3f3f3f3f;
struct node
{
    ll x, y;
    int id;
    bool operator < (const node &b) const {//重载小于号,按x从小到大排序
        if(x == b.x) return y < b.y;
        else return x < b.x;
    }
}a[N];
bool judge_k(ll *ky, ll *kx, int u, int v)//判断斜率是否相等
{
    ll y = a[u].y - a[v].y;
    ll x = a[u].x - a[v].x;
    if(*ky == inf) {
        *ky = y, *kx = x;
        return 1;
    }
    if(y**kx == *ky*x) return 1;
    else return 0;
}

double get_k(int u, int v)//获取斜率
{
    double y = a[u].y - a[v].y;
    double x = a[u].x - a[v].x;
    if(a[u].x == a[v].x) return inf;
    return 1.0*y/x;
}

int main()
{
    int n, i;
    scanf("%d", &n);
    for(i = 1; i <= n; i++) {
        cin >> a[i].x >> a[i].y;
        a[i].id = i;//记录一下下标
    }
    sort(a+1, a+1+n);//按x从小到大排序
    double Max = -inf, Min = inf;//记录最大斜率,最小斜率
    ll Maxy, Maxx, Miny, Minx;//记录最大斜率点,最小斜率点(都是到最左边的点)
    ll ky = inf, kx;
    int flag = 0;
    for(i = 2; i <= n; i++)
    {
        if(!judge_k(&ky, &kx, i, i-1)) {
            flag = 1;
        }
        double t = get_k(1, i);//求最大,最小斜率的点。
        if(Max < t)
            Max = t, Maxy = a[i].y, Maxx = a[i].x;
        if(Min > t)
            Min = t, Miny = a[i].y, Minx = a[i].x;
    }
    if(!flag) printf("-1\n");//如果斜率全一样,那么就是一条线
    else {
        for(i = 2; i <= n; i++)//输出n-1条边
            printf("%d %d\n", a[i].id, a[i-1].id);
        for(i = 3; i <= n; i++)//输出最大斜率边,或者最小斜率边 i从3开始,因为2已经连接过了。
        {
            if((a[i].x == Maxx && a[i].y == Maxy) || (a[i].x == Minx && a[i].y == Miny))
            {
                printf("%d %d\n", a[1].id, a[i].id);
                break;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值