【题解】直线交点数

题目信息

题目来源:未知;

在线评测地址: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 了、
}
posted @ 2020-08-27 16:24  5ab  阅读(128)  评论(0编辑  收藏  举报