递归算法-线的交叉点
平面上有n条直线,且无三线共点,问这些直线能有多少种不同交点数。
代码实现(递归):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | /**************************************************************** * 代码作者: Alex Li * 创建时间: 2024-02-21 11:15:32 * 最后修改: 2026-04-21 13:16:37 * 文件描述: 平面上有 n 条直线,且无三线共点,问这些直线能有多少种不同交点数。 ****************************************************************/ #include <iostream> using namespace std; // g[x] = true 表示:x 这个交点数是可以构造出来的 bool g[10000]; // s(n, j) n = 还有 n 条直线没有分组 j = 当前已经累计出的交点数 void s(int n, int j) { // 所有直线都已经分组完成,记录这种交点数 if (n == 0) { g[j] = true; return; } // 枚举:这次取出 i 条直线,作为“同一组平行线”, 这一组中的 i 条线彼此平行,所以组内不会产生交点。 // 但它们会与剩下的 n-i 条直线分别相交:当前组的每一条线,都会与另外 n-i 条线各交一次, // 因此新增交点数是 i * (n - i),然后递归处理剩下的 n-i 条直线。 for (int i = 1; i <= n; i++) { s(n - i, j + (n - i) * i); } } int main() { int n; cin >> n; s(n, 0); // 从“还没有分组、交点数为 0”开始递归 // n 条直线最多形成 n*(n-1)/2 个交点, 任意两条都相交时达到最大值 int maxn = n * (n - 1) / 2; for (int i = 0; i <= maxn; i++) { if (g[i]) cout << i << ' '; } return 0; } |
代码实现(DP):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /**************************************************************** * Description: 平面上有n条直线,且无三线共点,问这些直线能有多少种不同交点数。 * Author: Alex Li * Date: 2024-02-20 21:30:26 * LastEditTime: 2024-02-20 23:25:05 ****************************************************************/ #include <iostream> #include <vector> using namespace std; // 定义一个动态规划数组,dp[n][j]表示有n条线时,能产生j个交点的情况是否存在(1代表存在,0代表不存在) //int dp[20][190]; vector<vector<bool> > dp; int main(){ int n,b,maxn;// n表示线的数量,b是一个用于计算的辅助变量,maxn表示n条最多的交点数 cin>>n; dp.resize(n+1); maxn=n*(n-1)/2;//n条线最多n*(n-1)/2个交点 //初始化dp数组 for (int i = 0; i <=n; i++){ dp[i].resize(maxn+1,false); } dp[0][0]=1; // 初始化,0条线时0个交点的情况显然存在 dp[1][0]=1; // 初始化,1条线时0个交点的情况也显然存在 for(int i=2;i<=n;i++){ // 从2条线开始,逐步计算到n条线的情况 dp[i][0]=1; // 初始化,任何数量的线都有0个交点的情况(即它们都是平行) for (int j = 1; j <=i; j++){// 在i条直线中有j条直线是平行的 for (int k = 0; k <=i*(i-1)/2; k++){// 遍历所有可能的交点数 b=i-j; //b为i条直线减去j条平行线 if(dp[b][k]==1) //// 如果存在b条线产生k个交点的情况 dp[i][b*j+k]=1; //i条直线的交点方案数 = b*j+b条之间本身的交点方案数(1<=b<=i) } } } for (int i = 0; i <=maxn; i++){ if(dp[n][i]==1)cout<<i<<" "; } return 0; } |
