文章目录
题目链接:
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=C82⋅C62⋅C42⋅C22
然后8个点有4对,这4对排列是重复的
因此:
105=4!C82⋅C62⋅C42⋅C22
然后验证其他的,发现是对的
(二)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 */