题目信息
题目来源:未知;
在线评测地址:Luogu#2789;
运行限制:时间 (1.00 extrm{s}),空间 (256 extrm{MiB})。
题目描述
平面上有 (N) 条直线,且无三线共点,那么这些直线能有多少不同的交点数?
输入格式
一个正整数 (N)。
输出格式
一个整数表示方案总数。
数据规模及约定
(Nle 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)}lorcdotslor f_{i-k,j-k(i-k)}lorcdotslor f_{0,j})。特别地,(f_{0,0}=color{lime}{ extrm{True}})。
最后,统计一下 (sum[f_{n,k}=color{lime}{ extrm{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
", ans); // 输出
return 0; // 然后就 AC 了、
}