1. 程式人生 > >2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest B

2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest B

PS: 這是一道簽到題, RB強者 恐怖如斯。

Given an even number of distinct planar points, consider coupling all of the points into pairs. All the possible couplings are to be considered as long as all the given points are coupled to one and only one other point.

When lines are drawn connecting the two points of all the coupled point pairs, some of the drawn lines can be parallel to some others. Your task is to find the maximum number of parallel line pairs considering all the possible couplings of the points.

For the case given in the first sample input with four points, there are three patterns of point couplings as shown in Figure B.1. The numbers of parallel line pairs are 0, 0, and 1, from the left. So the maximum is 1.

Figure B.1. All three possible couplings for Sample Input 1

For the case given in the second sample input with eight points, the points can be coupled as shown in Figure B.2. With such a point pairing, all four lines are parallel to one another. In other words, the six line pairs (L1,L2)(L1,L2)

, (L1,L3)(L1,L3)

, (L1,L4)(L1,L4)

, (L2,L3)(L2,L3)

, (L2,L4)(L2,L4)

and (L3,L4)(L3,L4)

are parallel. So the maximum number of parallel line pairs, in this case, is 6. The input consists of a single test case of the following format. Inputmm

x1x1

y1y1

… xmxm

ymym

 Figure B.2. Maximizing the number of parallel line pairs for Sample Input 2 The first line contains an even integer mm

, which is the number of points (2≤m≤162≤m≤16

). Each of the following mm

lines gives the coordinates of a point. Integers xixi

and yiyi

(−1000≤xi≤1000,−1000≤yi≤1000−1000≤xi≤1000,−1000≤yi≤1000

) in the ii

-th line of them give the xx

  • and yy

-coordinates, respectively, of the ii

-th point. The positions of points are all different, that is, xi≠xjxi≠xj

or yi≠yjyi≠yj

holds for all i≠ji≠j

. Furthermore, No three points lie on a single line. Output Output the maximum possible number of parallel line pairs stated above, in one line. Sample Input 14 0 0 1 1 0 2 2 4 Sample Output 11 Sample Input 28 0 0 0 5 2 2 2 7 3 -2 5 0 4 -2 8 2 Sample Output 26 Sample Input 36 0 0 0 5 3 -2 3 5 5 0 5 7 Sample Output 33 Sample Input 42 -1000 1000 1000 -1000 Sample Output 40 Sample Input 516 327 449 -509 761 -553 515 360 948 147 877 -694 468 241 320 463 -753 -206 -991 473 -738 -156 -916 -215 54 -112 -476 -452 780 -18 -335 -146 77 Sample Output 512

題意: 給出n個點 要將這些點兩兩配對構成線段,使得互相平行的線段數X最多 輸出X*(X-1)/2

解題思路: 最多16個點,很容易想到列舉和狀壓。 斜率的種類是O(m^2)級別的。 考慮列舉斜率。 設dp[i] 表示i這種狀態 組成同一種斜率的最大價值是多少。很顯然,這是個揹包DP。 複雜度也很好估計 最多合法的情況是C(2,16)+C(4,16)+C(6,16)+…+C(16,16); 這是是O(n^2)的。 所以DP複雜度是O((216 *(m2)) 預處理複雜度是O((216 *(m3)) 感覺很棒。 日本簽到題,恐怖如斯。

#include <bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, int> pdi;
const int MAX = 20;
int m;
class Node{
public:
    int x,y;
};
bool vis[MAX];
int check(int x,int y,vector<Node> &node){
    int ans =0;
    memset(vis,0,sizeof vis);
    for(int i=0;i<node.size();i++){
        if(vis[i]) continue;
        int j=i+1;
        while(j<node.size()){
            if(vis[j]){
                j++;
                continue;
            }
            if(y*(node[i].x-node[j].x)==x*(node[i].y-node[j].y)){
                vis[j]=1;
                ans++;
                break;
            }
            j++;
        }
    }
    return ans;
}
Node node[MAX];
int check(int S){
    vector<Node> X;
    vector<Node> V;
    for(int i=0;i<m;i++){
        if((1<<i) & S){
            X.push_back(node[i]);
        }
    }
    for(int i=0;i<X.size();i++){
        for(int j=i+1;j<X.size();j++){
            Node cnt;
            cnt.x = X[i].x-X[j].x;
            cnt.y = X[i].y-X[j].y;
            V.push_back(cnt);
        }
    }
    int ans = 0;
    for(int i=0;i<V.size();i++){
        ans = max(ans,check(V[i].x,V[i].y,X));
    }
    if(ans *2 == X.size()){
        //cout<<ans<<endl;
        return ans*(ans-1)/2;
    }else{
        return -1;
    }
}
int dp[(1<<16)+10];
int main(){
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        scanf("%d %d",&node[i].x,&node[i].y);
    }
    vector<int> OP;
    for(int i=0;i<(1<<m);i++){
        int cnt = check(i);
        if(cnt!=-1){
            //cout<<"i:"<<i<<","<<cnt<<endl;
            dp[i]=cnt;
            OP.push_back(i);
        }
    }
    int ans = 0;
    for(int i=0;i<OP.size();i++){
        for(int S=(1<<m)-1;S>=0;S--){
            if(S&OP[i]) continue;
            dp[S|OP[i]]=max(dp[S|OP[i]],dp[S]+dp[OP[i]]);
            ans = max(ans,dp[S|OP[i]]);
        }
    }
    cout<<ans<<endl;
}