题目链接:HDU6976
题目描述:
Alice 和 Bob 玩一个游戏,有 n n n 条直线在 2D 平面上。Alice 先选择其中的 k k k 条直线,然后 Bob 画一条直线 L L L。Bob 的花费是这条直线 L L L 与 k k k 条直线相交的直线的个数。现在,Alice 想要尽可能的使这个花费大,而 Bob 要使这个花费尽可能小。在双方都采取最有策略的情况下,求 k = 1 , 2 , … … , n k = 1,2,……,n k=1,2,……,n 时的花费。
输入数据的格式为,第一行输入测试样例组数。对于每组测试样例,输入一个正整数 n,接下来 n 行,输入 x a i xa_i xai, y a i ya_i yai, x b i xb_i xbi, y b i yb_i ybi,表示一条直线。
输出数据的格式为,对于每组测试样例,输出 n n n 行,每行输出一个整数,表示 k = i k = i k=i 时的花费。
题目解析:
不难想,Alice 会优先选择斜率不同的直线,使得尽可能少的直线平行,Bob 所画的直线 L 一定是与当前平面上斜率相同的直线最多的那条直线平行。
参考代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define abs(x) x > 0 ? x : -x
using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 10;
pii a[N];
int cnt[N]; // 存储斜率不同直线个数
int gcd(int a, int b) {
return b == 0? a : gcd(b, a % b); }
int main() {
int t;
scanf("%d", &t);
while (t--) {
memset(cnt, 0, sizeof(cnt));
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x1, x2, y1, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int dx = x2 - x1, dy = y2 - y1;
if (dx == 0)
dy = 1;
else if (dy == 0)
dx = 1;
else {
if (dx < 0) dx = -dx, dy = -dy;
int g = gcd(abs(dx), abs(dy));
dx /= g, dy /= g;
}
a[i] = pii(dx, dy);
}
sort(a + 1, a + 1 + n);
int p1, p2;
for (p1 = 1; p1 <= n; p1 = p2) {
for (p2 = p1; p2 <= n && a[p1] == a[p2]; p2++);
for (int k = 1; k <= p2 - p1; k++)
cnt[k]++;
}
for (p1 = p2 = 1; p1 <= n; p1++) {
while (!cnt[p2])
p2++;
cnt[p2]--;
printf("%d\n", p1 - p2);
}
}
return 0;
}