问题重述:
平面上有n条直线,且无三线共点,问这些直线能有多少种不同交点数。 比如,如果n=2,则可能的交点数量为0(平行)或者1(不平行)。
输入:
输入数据包含多个测试实例,每个测试实例占一行,每行包含一个正整数n(n<=20),n表示直线的数量.
输出:
每个测试实例对应一行输出,从小到大列出所有相交方案,其中每个数为可能的交点数,每行的整数之间用一个空格隔开。
样例输入:
2
3
样例输出:
0 1
0 2 3
题解:
n条直线,交点最大为n*(n-1)/2。
当n=1, 2, 3时,交点个数易知为(0), (0, 1), (0, 2, 3),当n=4时,分一下四种情况:
1. 四条线都平行,交点为 0;
2. 三条线平行,交点个数为 3*(n-3)[第4条线与前三条线交点数] + 0[第4条线自身交点数U1];
3. 两条线平行,交点个数为 2*(n-2)[第3, 4条线与前两条线交点数] + 0 or 1[第3, 4条线之间的交点数U2];
4. 一条线平行(都不平行),交点个数为1*(n-1) + 0 or 2 or 3[第2, 3, 4条线之间交点数U3];
由此可知n条线的交点数为 Un = { i*(n-i) + Un-i }, for 0 <= i < n; 其中集合的加法是 元素分别加集合中的每一元素。得出伪代码:
U0 = {0}, U1 = {0}
for n=2 to N:
Un = {};
for i = 1 to n:
Un = Un U {i*(n-i)+Un-i};
代码实现如下:
利用c[i][j]=1表示i条线包含j个交点这一项,从而实现并运算。
#include <iostream>
using namespace std;
int main(){
int c[21][200] = {0}; //20条线最后有200个交点
for(int i = 0; i < 21; i++) //任意i条直线必有0个交点这一项(全部平行)
c[i][0] = 1;
for(int n = 2; n < 21; n++){ //集合大小n从2到20
for(int i = 1; i < n; i++){ //对于任意i条平行直线(1<=i<n)
for(int j = 0; j < 200; j++){ //判断200个交点项的每一项
if(c[n-i][j]) c[n][i * (n - i) + j] = 1; //Un = { Un U Un-i + i*(n-i) }
}
}
}
int n, max;
while(cin >> n){
max = n*(n-1)/2;
for(int i = 0; i <= max; i++)
if(c[n][i]) cout << i << " ";
cout << endl;
}
return 0;
}