Codeforces-961D Pair Of Lines

题目链接:

CF-961D

题目大意:

给平面上 N N 个点,问是否存在两条直线(可重合)使得每个点至少在某一条直线上?

数据范围:

1N105|xi|,|yi|109 1 ≤ N ≤ 10 5 | x i | , | y i | ≤ 10 9

解题思路:

任选 3 3 个点,在其中选 2 个点,使之为一条直线,把在这条直线上的点删掉,然后判断其余的点是否在另一条直线上。(叉积判共线)


AC代码:

/********************************************
 *Author*        :XzzF
 *Created Time*  : 2018年04月06日 星期五 16时27分02秒
 * Ended  Time*  : 2018年04月06日 星期五 16时57分14秒
*********************************************/

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
const int MaxN = 100005;

int n;
bool used[MaxN + 5];
struct Point {
    LL x, y;
    Point () {}
    Point (LL _x, LL _y) {
        x = _x; y = _y;
    }
    friend Point operator - (const Point A, const Point B){
        return Point (A.x - B.x, A.y - B.y);
    }
}PP[MaxN + 5];

typedef Point Vector;

LL Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}

bool check() {
    int Na = -1, Nb = -1;
    for(int i = 1; i <= n; i++) {
        if(used[i]) continue;
        if(Na == -1) Na = i;
        else if(Nb == -1) Nb = i;
    }
    if(Na == -1 || Nb == -1) return true;
    for(int i = 1; i <= n; i++) {
        if(used[i]) continue;
        if(Cross(PP[Nb] - PP[Na], PP[i] - PP[Na]) != 0)
            return false;
    }
    return true;
}

bool judge (Point A, Point B) {
    memset(used, 0, sizeof(used));
    for(int i = 1; i <= n; i++) {
        if(Cross(B - A, PP[i] - A) == 0)
            used[i] = true;
    }
    return check();
}

bool solve() {
    if(n <= 3) return true;
    if(judge(PP[1], PP[2]) || judge(PP[1], PP[3]) || judge(PP[2], PP[3]))
        return true;
    return false;
}

int main()
{
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 1; i <= n; i++) 
            scanf("%lld %lld", &PP[i].x, &PP[i].y);
        if(solve() ) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}





赛后听到大佬们随机过的!(Orz) 嗯???还有这种骚操作?


果断学习一下!
主要就是随机两个点,删除在这条直线上的点,再判断其余的点是否在一条直线上。


似乎有种似曾相识的感觉?


随机代码:

/**********************************************
 *Author*        :XzzF
 *Created Time*  : 2018/4/11 10:37:54
 *Ended  Time*  : 2018/4/11 10:47:34
 *********************************************/

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
const int MaxN = 100005;

int n;
bool used[MaxN + 5];
struct Point {
    LL x, y;
    Point () {}
    Point (LL _x, LL _y) {
        x = _x; y = _y;
    }
    friend Point operator - (const Point A, const Point B){
        return Point (A.x - B.x, A.y - B.y);
    }
}PP[MaxN + 5];

typedef Point Vector;

LL Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}

bool check() {
    int Na = -1, Nb = -1;
    for(int i = 1; i <= n; i++) {
        if(used[i]) continue;
        if(Na == -1) Na = i;
        else if(Nb == -1) Nb = i;
    }
    if(Na == -1 || Nb == -1) return true;
    for(int i = 1; i <= n; i++) {
        if(used[i]) continue;
        if(Cross(PP[Nb] - PP[Na], PP[i] - PP[Na]) != 0)
            return false;
    }
    return true;
}

bool judge (Point A, Point B) {
    memset(used, 0, sizeof(used));
    for(int i = 1; i <= n; i++) {
        if(Cross(B - A, PP[i] - A) == 0)
            used[i] = true;
    }
    return check();
}

bool solve(Point A, Point B) {
    if(n <= 3) return true;
    if(judge(A, B) )
        return true;
    return false;
}

int main()
{
    srand(time(NULL));
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 1; i <= n; i++) 
            scanf("%lld %lld", &PP[i].x, &PP[i].y);
        bool f = 0;
        if(n <= 3) f = 1;
        else {
            for(int i = 1; i <= 200; i++) {
                int a = rand() % n + 1;
                int b = rand() % n + 1;
                while(a == b) b = rand() % n + 1;
                if(solve(PP[a], PP[b])) {
                    f = 1;
                    break;
                }
            }
        }
        if(f) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值