[UVALive 6955 Finding Lines]概率+随机算法

[UVALive 6955 Finding Lines]概率+随机算法

知识点:math probability random algorithm

1. 题目链接

[UVALive 6955 Finding Lines]

2. 题意描述

n 个顶点,坐标记为 (xi,yi) ,求是否存在一条这样的直线,覆盖至少 p% 的点。
1n105,0xi,yi109,20p100

3. 解题思路

比较直接的想法是 O(N2) 的去暴力枚举。显然不行。
但是,注意到这个题目 20p100 这个条件。细细分析一下。需要有一条直线覆盖 20% 的点,在点完全均匀离散的时候,实际上概率是比较小的。
考虑随机选取 2 个顶点来枚举每条直线。假设存在 p% 的点在同一条直线上。那么从 n 个点中任意选出 2 个顶点构成该直线,选中的概率为 (p100)2 ,没选中的概率为 [1(p100)2] 。当我随机 t 次时,那么依旧没有选中该直线的概率就为 [1(p100)2]t ,那么显然,当 t 够大的时候,这个没有选中的概率是相当小的,极速收敛于 1
随机次数 t 的确定可以这样做:
p 最小 p=20 ,

[1(p100)2]t=(2425)t

我们可以取 t[200,1000] 。太大了会TLE,因为每次需要 O(n) 的统计在直线上的点。

4. 实现代码

#include 
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair PLL;

const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;

int n, p;
LL x[MAXN], y[MAXN];
bool ans;

void run() {
    int a = rand() % n;
    int b = rand() % n;
    while(b == a) b = rand() % n;
    LL up = x[a] - x[b], dw = y[a] - y[b];
    LL cnt = 2;
    for(int i = 0; i < n; i++) {
        if(i == a || i == b) continue;
        LL uup = x[i] - x[b], ddw = y[i] - y[b];
        if(up * ddw == uup * dw) cnt ++;
    }
    if(n * p <= cnt * 100) ans = true;
}
int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    srand(12);
    while(~scanf("%d", &n)) {
        scanf("%d", &p);
        ans = false;
        for(int i = 0; i < n; i++) scanf("%lld %lld", &x[i], &y[i]);
        if(n <= 2) {
            puts("possible");
            continue;
        }
        int t = 200;
        while(t --) {
            run();
            if(ans) break;
        }
        puts(ans ? "possible" : "impossible");
    }
    return 0;
}

你可能感兴趣的:(ACM____数,学)