【随机算法】(NWERC2014) F-Finding Lines

题目描述

给n个点,求是否至少存在(n * p / 100)个点在一条直线上

思路

暴力显然是不可取的,翻阅了题解学习该题,也是第一次接触这样的随机算法。
如果存在一条线满足情况,有m个点在这条直线上,选取任意两个点,选中的一个点的在直线上的概率是 m n \frac{m}{n} nm,选另一个点的恰好也在直线上的概率就是 ( m − 1 ) n \frac{(m-1)}{n} n(m1),就变成选中这条直线的概率是 m ∗ ( m − 1 ) n ∗ n \frac{m*(m-1)}{n * n} nnm(m1),选不中这条直线的概率变成了 t = ( 1 − m ∗ ( m − 1 ) n ∗ n ) t = (1-\frac{m*(m-1)}{n*n}) t=(1nnm(m1)),然后应该随机选1000次,全部选不中的概率就是t1000, t < 1 t <1 t<1,1000次方以后接近于0,就随机枚举1000次了,没有随机取到就impossible

代码

#include
using namespace std;

typedef long long LL;

const int N = 1e5 + 10;
struct node {
	LL x, y;
}a[N];
int n, p;

void solve() {
	for(int i = 1; i <= n; i++) {
		scanf("%lld%lld", &a[i].x, &a[i].y);
	}

	if(n <= 2) {
		puts("possible");
		return;
	}

	int t = 1000;
	int num = ceil(n * p * 1.0 / 100);
	srand(time(0));
	while(t--) {
		int p1 = (LL)rand() * rand() % n + 1;
		int p2 = (LL)rand() * rand() % n + 1;
		while(p1 == p2) p2 = rand() % n + 1;

		LL x1 = a[p2].x - a[p1].x, y1 = a[p2].y - a[p1].y;
		int cnt = 0;
		for(int i = 1; i <= n; i++) {
			LL x2 = a[i].x - a[p1].x, y2 = a[i].y - a[p1].y;
			if(x1 * y2 == x2 * y1) cnt++;
		}
		if(cnt * 100 >= n * p) {
			puts("possible");
			return;
		}
	}
	puts("impossible");

}

int main() {
	//freopen("in.txt", "r", stdin);
	while(~scanf("%d%d", &n, &p))
		solve();
	return 0;
}

你可能感兴趣的:(Gym)