【题解】直线交点数
题目信息
题目来源:未知;
在线评测地址: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 了、
}
本文来自博客园,作者 5ab,转载请注明链接哦 qwq
博客迁移啦,来看看新博客吧 -> https://5ab-juruo.oier.space/