【題解】直線交點數
阿新 • • 發佈:2020-08-27
目錄
題目資訊
題目來源:未知;
線上評測地址:Luogu#2789;
執行限制:時間 \(1.00\ \textrm{s}\),空間 \(256\ \textrm{MiB}\)。
題目描述
平面上有 \(N\) 條直線,且無三線共點,那麼這些直線能有多少不同的交點數?
輸入格式
一個正整數 \(N\)。
輸出格式
一個整數表示方案總數。
資料規模及約定
\(N\le 25\)。
分析
題意很清晰,但是要想到正解是比較難的。
不考慮重合,平面上的兩條直線只有平行和相交兩種情況。每一組直線相交就會多一個交點。
同時,平行具有傳遞性,也就是說對於一組平行的直線,之間沒有任何交點。我們定義一組(\(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 了、 }