题目链接:

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1379
https://vjudge.net/contest/270706#problem/B

题意:给了N个点,问能最多能选出几对直线的斜率相同,斜率可能有多种,点不能重复使用

比赛的时候想把斜率预处理出来,然后枚举能组成这个斜率的直线有多少个
但是后来发现点不能重复使用。。。而这种方法弄出来的点的重复使用了的,所以就不行

然后看题解说直接暴力判断,我还想说暴力力题啊,不做了不做了,但是仔细想想暴力要怎么暴力喃?好像我还不怎么会暴力T_T,还是做一哈算了,结果。。。幸好做了,感觉这道题对我来说其实很有价值~

(一)计算复杂度

首先这个算复杂度的时候我***了,我写了个dfs发现诶怎么符合条件的方案怎么那么多???
N=4:6种
N=6:90种
N=8:2520种

我觉得不应该是这么多啊,N=4的时候都只有3种呀
(1,2)(3,4)
(1,3)(2,4)
(1,4)(2,3)
N=4应该只有这三种
应该是有重复的

然后专门写了个暴力来跑,用的排列来暴力,好像算到12就算不动了T_T
N=4:3种
N=6:15种
N=8:105种

然后用前几项去OEIS查,发现竟然是个双阶乘的数列,双阶乘我还以为是阶乘的阶乘勒,结果要么是偶数的阶乘,要么是奇数的阶乘。

后来我反应过来了,上面N=8的时候有重复的是2520种,无重复的是105种是怎么来的了

每次选两种:
2520 = C 8 2 C 6 2 C 4 2 C 2 2 2520=C_8^2\cdot C_6^2\cdot C_4^2\cdot C_2^2 2520=C82C62C42C22

然后8个点有4对,这4对排列是重复的
因此:
105 = C 8 2 C 6 2 C 4 2 C 2 2 4 ! 105=\frac{C_8^2\cdot C_6^2\cdot C_4^2\cdot C_2^2}{4!} 105=4!C82C62C42C22

然后验证其他的,发现是对的

(二)dfs两重循换变一重

解决了上面的问题我又写了一发,跑最后一个样例的时候发现用了12000ms+
看别人的代码我惊讶地发现为什么别人的dfs里面只有一层循环呀???一次选两个数让我想怎么也要写两个for循环才行呀~
哇,原来别人是这样的:
首先看当前这个数能不能用
①:要是阔以用,那就用for循环再找另一个阔以用的数
②:如果不能用,就直接进入下一层dfs
哇,这样时间上测出来就直接少了4000ms+

最后统计答案那里,我开始是用map统计这种斜率的直线的个数来计算,改成两层for循环直接暴力,速度瞬间变成了1000ms+了,快了8倍左右。。。

#include"bits/stdc++.h"
#define out(x) cout<<#x<<"="<<x
#define C(n,m) (m>n?0:(long long)fac[(n)]*invf[(m)]%MOD*invf[(n)-(m)]%MOD)
using namespace std;
typedef long long LL;
const int maxn=1e2+5;
const int MOD=1e9+7;
int FULL,Max;
int a[maxn],t;
struct Point
{
	int x,y;
	Point() {}
	Point(int x,int y):x(x),y(y) {}
};
Point P[maxn];
pair<int,int>Slope[maxn][maxn];//怕用double炸精度啥的,所以用pair来表示斜率
int N;
int f()
{
	int res=0;
// map<pair<int,int>,int>Mp;
// for(int i=1; i<N; i+=2)Mp[Slope[a[i]][a[i+1]]]++;
// for(auto i:Mp)
// {
// int n=i.second;
// if(n>=2)res+=n*(n-1)/2;
// }

	//for循环快8倍 
	for(int i=1; i<=N; i+=2)
	{
		for(int j=i+2; j<=N; j+=2)
		{
			int dx=Slope[a[i]][a[i+1]].first;
			int dy=Slope[a[i]][a[i+1]].second;
			int tx=Slope[a[j]][a[j+1]].first;
			int ty=Slope[a[j]][a[j+1]].second;
			if(dx==tx&&dy==ty)res++;
		}
	}
	return res;
}
int cnt;
void dfs(int STA,int now)
{
	cnt++;
	if(STA==FULL)
	{
		Max=max(Max,f());
		return ;
	}
	if(STA&(1<<now))dfs(STA,now+1);//如果当前这个不能选,直接进入下一个dfs
	else
	{
		for(int i=1; i<=N; i++)
		{
			if(now==i)continue;
			if(STA&(1<<i))continue;
			int sta=STA|(1<<i);
			sta|=(1<<now);
			a[++t]=now,a[++t]=i;//同时选now和i
			dfs(sta,now+1);
			t-=2;
		}
	}
}
clock_t t1,t2;
int main()
{
	while(cin>>N)
	{
		t=Max=FULL=0;
		for(int i=1; i<=N; i++)
		{
			cin>>P[i].x>>P[i].y;
			FULL|=(1<<i);
		}
		for(int i=1; i<=N; i++)//预处理出斜率
		{
			for(int j=i+1; j<=N; j++)
			{
				int x=P[i].x-P[j].x;
				int y=P[i].y-P[j].y;
				if(x==0)y=1;
				else if(y==0)x=1;
				else
				{
					int d=__gcd(x,y);
					x/=d,y/=d;
				}
				Slope[i][j]=Slope[j][i]=make_pair(x,y);

			}
		}
		t1=clock();
		cnt=0;
		dfs(0,1);
// cout<<"cnt="<<cnt<<endl;
		t2=clock();
// cout<<"time="<<t2-t1<<endl;
		cout<<Max<<endl;

	}
}

/* 16 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 */