题意:Alice和Bob正在玩游戏,在这个游戏中,2d平面上共有n条直线。Alice会在所有 n 条直线中选择 k 条直线 l1、l2、…、lk,然后Bob将绘制额外的一条直线 L。对 Bob 的惩罚定义为 L 与Alice选择的 k 条直线有交点的直线的数量。(请注意,两条重叠线也算有交点。)
Alice想最大化对 Bob 的处罚,而 Bob 想最小化处罚。你将得到这n行,请编写一个程序来预测当 k = 1, 2, 3,…,n时,如果两个玩家都发挥最佳状态,求Bob 的惩罚。
输入描述:
第一行包含一个整数T(1 ≤ T ≤ 500),表示测试用例的数量。对于每个测试用例:第一行包含一个整数 n(1 ≤ N ≤ 100000),表示直线的数量。接下来的n行中的每一行都包含四个整数xai、yai、xbi和ybi(0 ≤ xai,yai,xbi,ybi ≤ 10^9),表示一条直线同时经过(xai,yai)和(xbi,ybi)((xai,yai)永远不会与(xbi,ybi)重合,保证所有n的总和不超过1000000。)
输出描述:
对于每个测试用例,输出 n 行,第 i 行(1 ≤ i ≤ n) 其中包含一个整数,表示 k = i 时Bob的惩罚。
思路:Alice 会从n条直线中优先选择斜率不同的直线,使得k条直线中尽可能少的直线平行,Bob 所画的直线 L 一定是与当前平面上 Alice 所选的斜率相同的直线最多的那条直线平行。
accode:
#include <stdio.h>
#include <map>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 +10;
map<pair<int, int>, int> mp;
int num[maxn];
int gcd(int a, int b) //a和b的最大公约数
{
if(b == 0)
return a;
else
gcd(b, a % b);
}
int main()
{
int T, n, x1, y1, x2, y2;
scanf("%d", &T);
while(T--)
{
mp.clear();
memset(num, 0, sizeof(num));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d%d", &x1, &y1, & x2, &y2);
x1 -= x2;
y1 -= y2;
int k = gcd(x1, y1);
x1 /= k;
y1 /= k;
mp[make_pair(x1, y1)]++;
}
for(auto i : mp)
for(int j = 1; j <= i.second; j++)
num[j]++;
for(int i = 1, j = 1; i <= n; i++)
{
if(!num[j]) j++;
num[j]--;
printf("%d\n", i - j);
}
}
return 0;
}