思路讲解
我们在添加第 i i i 条边时,最多会和 i − 1 i-1 i−1 条边产生交点,所以交点数最多为 ∑ i = 1 n i − 1 \sum^{n}_{i=1}i-1 ∑i=1ni−1,即 ( 0 + n − 1 ) × n ÷ 2 ≈ n 2 (0+n-1)\times n \div 2\approx n^2 (0+n−1)×n÷2≈n2,而 n ≤ 25 n\le25 n≤25,所以方案数肯定不会超过 2 5 2 + 1 25^2+1 252+1,更不可能超过 1 0 9 + 7 10^9+7 109+7,所以根本不需要取模。
手玩几组样例,可以发现,每一种方案都可以被划分成若干组直线,使得每组内中的直线互相平行,或大小为 1 1 1,并且不同组的直线一定相交。设第 i i i 组直线为 l i l_i li,总共有 m m m 组,我们可以发现,由于前面的因素,第 i i i 组直线和别的直线的交点数为 n − l i n-l_i n−li,所以该方案的交点数为 ∑ i = 1 m n − l i \sum^{m}_{i=1}n-l_i ∑i=1mn−li 除以 2 2 2。除以 2 2 2 是因为一个交点会被相交于它的两条直线的组重复计算。
解法就很简单了,dfs
求出每种分组的方法,并将交点数存入
s
e
t
set
set 中去重,最后输出 set
的大小即可。时间复杂度最坏为
O
(
2
n
)
O(2^n)
O(2n)。
代码实现
#include <bits/stdc++.h>
using namespace std;
int n,sum;
set<int> s;
void dfs(int last,int rest){
//last代表上一次的选择,rest为剩余的边数
if(rest==0){//如果没有边没被分组
s.insert(sum/2);//存入答案
return;
}
for(int i=last;i<=rest;i++){
sum+=i*(n-i);//sum统计交点数
dfs(i,rest-i);
sum-=i*(n-i);//回溯
}
}
int main(){
scanf("%d",&n);
dfs(1,n);
printf("%d",s.size());
//输出答案
return 0;
}