2021“MINIEYE杯”中国大学生算法设计超级联赛 1004. Game on Plane(几何)

Problem Description

Alice and Bob are playing a game. In this game, there are n straight lines on the 2D plane. Alice will select exactly k straight lines l1,l2,…,lk among all the n straight lines first, then Bob will draw a straight line L. The penalty of Bob is defined as the number of lines in {l1,l2,…,lk} that shares at least one common point with L. Note that two overlapping lines also share common points.

Alice wants to maximize the penalty of Bob while Bob wants to minimize it. You will be given these n lines, please write a program to predict the penalty of Bob for k=1,2,3,…,n if both of the players play optimally.

Input

The first line contains a single integer T (1≤T≤500), the number of test cases. For each test case:

The first line contains a single integer n (1≤n≤100000), denoting the number of straight lines.

Each of the next n lines contains four integers xai,yai,xbi and ybi (0≤xai,yai,xbi,ybi≤109), denoting a straight line passes both (xai,yai) and (xbi,ybi). (xai,yai)will never be coincided with (xbi,ybi).

It is guaranteed that the sum of all n is at most 1000000.

Output

For each test case, output n lines, the i-th (1≤i≤n) of which containing an integer, denoting the penalty of Bob when k=i.

Sample Input

2
2
1 1 2 2
0 0 2 3
3
1 1 2 2
1 1 2 2
3 2 5 4

Sample Output

0
1
0
0
0

题意是Alice提前给出n条直线,然后Alice不断从中任意选择1、2...n条直线,使得以最优策略作一条直线后新的直线与选出来的直线交点数最多。

首先把n条直线读进来,分别求出每种斜率对应多少条直线,斜率可以用结构体存(本身就是y2 - y1与x2 - x1的比值,注意要用gcd进行约分),维护数目可以用map。然后遍历map把这些数目从大到小排序,每次尽可能选不一样的斜率即可。

注意特判斜率不存在的情况!以及要处理斜率为负的情况(可以把负号给第一个元素)

#include<bits/stdc++.h>
typedef long long ll; 
#define int long long
using namespace std;
int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
signed main(){
    int T;
    scanf("%lld",&T);
    while(T--){
        int n;
        scanf("%lld",&n);
        map<pair<int,int>,int> mp;
        int x1,y1,x2,y2,x,y;
        for(int i=0;i<n;i++){
            scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
            x=x2-x1,y=y2-y1;
            bool flag = ((x < 0) ^ (y < 0));
            if(x < 0) x = -x;
            if(y < 0) y = -y;
            int comm=gcd(x,y);
            if(flag) x = -x;
            pair<int,int> p;
            if(x1 == x2) {//斜率不存在
                p = make_pair(0,1);
            } else if(y1 == y2) {//斜率为0
                p = make_pair(1,0);
            } else p = make_pair(x/comm,y/comm);
            if(!mp[p]){ mp[p]=1;}//维护p这种斜率对应的数目
            else mp[p]++;
        } 
        map<pair<int, int>, int>::iterator it;
        vector<int> v;
        for(it = mp.begin(); it != mp.end(); it++) {
            v.push_back(it->second);
        }
        sort(v.begin(), v.end(), greater<int>());
        int len = v.size();
        int pos = 0;
        int round = 0;//一趟趟遍历
        for(int i = 1; i <= n; i++) {
            if(!v[pos] || pos == len) pos = 0, round++;//当前这种已经用光了或者遍历到头了,直接进行下一轮
            printf("%lld
", i - round - 1);
            v[pos]--;//用一种
            pos++;
        }
    } 
    return 0;
}
// 1
// 6
// 1 2 3 4
// 1 2 3 4
// 9 8 7 600
// 1 10 2 9
// 1 1001 900 800
// 5 9 1 3


// 5
// 5
// 0 0 1 1
// 1 1 0 0
// 0 0 1 1
// 1 2 3 9
// 3 9 1 2
原文地址:https://www.cnblogs.com/lipoicyclic/p/15068437.html