1. 程式人生 > 實用技巧 >【題解】直線交點數

【題解】直線交點數

目錄

題目資訊

題目來源:未知;

線上評測地址:Luogu#2789

執行限制:時間 \(1.00\ \textrm{s}\),空間 \(256\ \textrm{MiB}\)

題目描述

平面上有 \(N\) 條直線,且無三線共點,那麼這些直線能有多少不同的交點數?

輸入格式

一個正整數 \(N\)

輸出格式

一個整數表示方案總數。

資料規模及約定

\(N\le 25\)

分析

題意很清晰,但是要想到正解是比較難的。

不考慮重合,平面上的兩條直線只有平行和相交兩種情況。每一組直線相交就會多一個交點。

同時,平行具有傳遞性,也就是說對於一組平行的直線,之間沒有任何交點。我們定義一組(\(k\)

個)平行線為一個大小為 \(k\) 的線簇。

如果現在有兩個大小分別為 \(a\)\(b\) 的線簇相交,那麼就會產生 \(ab\) 個交點。如果我們統計交點時以線簇為單位統計,就可以達到比較優秀的複雜度。

考慮 DP,令 \(f_{i,j}\)\(i\) 條直線時能否產生 \(j\) 個節點。轉移時,列舉大小在 \(1\)\(i\) 的線簇,\(f_{i,j}=f_{i-1,j-(i-1)}\lor f_{i-2,j-2(i-2)}\lor\cdots\lor f_{i-k,j-k(i-k)}\lor\cdots\lor f_{0,j}\)。特別地,\(f_{0,0}=\color{lime}{\textrm{True}}\)

最後,統計一下 \(\sum[f_{n,k}=\color{lime}{\textrm{True}}]\) 即可。

當然,這道題也可以搜尋解答。

Code

這道題程式碼需要注意一下迴圈的邊界。

#include <cstdio>
using namespace std;

const int max_n = 25;
bool dp[max_n+1][max_n*max_n] = {}; // dp[0..n][0..n^2-1]

int main()
{
	int n, ans = 0;

	scanf("%d", &n); // 輸入

	dp[0][0] = 1;
	for (int i = 1; i <= n; i++) // 直線的數量
		for (int j = 0; j < n * n; j++) // 節點的數量
			for (int k = 1; k <= i; k++) // 線簇的大小
				dp[i][j] |= dp[i-k][j-(i-k)*k]; // 轉移
	
	for (int i = 0; i < n * n; i++) // 統計答案
		ans += dp[n][i];

	printf("%d\n", ans); // 輸出
	
	return 0; // 然後就 AC 了、
}