1. 程式人生 > >Aizu 1379 Parallel Lines

Aizu 1379 Parallel Lines

文章目錄

題目連結:

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

然後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!}

然後驗證其他的,發現是對的

(二)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
*/