链接:https://ac.nowcoder.com/acm/contest/911/A
来源:牛客网
题目描述
平面上给 n(3≤n≤1000) 个点,保证不存在 3 点共线,保证这些点两两不重合,对于一个点集 S ,如果从 S 中任意选出三个不同的点,构成的三角形重心都不是整点(横坐标,纵坐标都是整数的点,称为整点),那么这个点集是 good 的,输出最大的 good 的点集大小。(注:所有点数小于等于 2 的点集都是 good 的)。
输入描述:
第一行,一个整数 n(3≤n≤1000),表示 n 个点,之后 n 行,每行两个整数 x[i],y[i](0≤x[i],y[i]≤10^6).
输出描述:
输出一个正整数表示答案。
示例1
输入
4 0 0 0 1 1 0 1 1
输出
4
示例2
输入
3 0 0 1 2 2 1
输出
2
备注:
* 样例 1 所有点都可以加入集合。 * 样例 2,如果 3 个点同时加入集合,重心为 (1,1) 不合法,Good Set 中至多只能 2 个点。
题解:
重心公式 x=(x1+x2+x3)/3, y=(y1+y2+y3)/3;
那么首先我们可以将每个点的横纵坐标都模3.那么实际上终于9类型的点,(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2).
并统计一下每类型点的个数。
显然,每类型的点最多只能选两个,因为如果选了3个,那么这三个点构成的三角形重心就是整数坐标了,这9类型的点我们可以用二进制去枚举选哪几个,然后check是否合法,取合法里的最大值即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
pair<int,int> p[10];
int cnt[10];
int n,m;
int a[3][3];
vector<pair<int,int> > v;
bool judge(int i,int j,int k){
if((v[i].first+v[j].first+v[k].first)%3==0&&(v[i].second+v[j].second+v[k].second)%3==0) return true;
return false;
}
bool check(){
for(int i=0;i<v.size();i++){
for(int j=i+1;j<v.size();j++){
for(int k=j+1;k<v.size();k++){
if(judge(i,j,k)) return false;
}
}
}
return true;
}
int main(){
cin>>n;
while(n--){
int x,y;
scanf("%d%d",&x,&y);
a[x%3][y%3]++;
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(a[i][j]==0) continue;
int x=min(2,a[i][j]);
p[m].first=i;p[m].second=j;
cnt[m]=x;
m++;
}
}
int ans=0;
for(int i=1;i<(1<<m);i++){
v.clear();
int t=0;
for(int j=0;j<m;j++){
if(i>>j&1) v.push_back(p[j]),t+=cnt[j];
}
if(check()) ans=max(ans,t);
}
cout<<ans<<endl;
return 0;
}