试题题目原题:
本题答案:40257 解题思路: ??一、在平面直角坐标系统XOY中,有点集{(x,y)|0≤x<2,0≤y<3,x ? Z,y ? Z},确定了2×3=6个点。每两个点都能确定一条直线,那么该六个点就能确定
(
6
2
)
?
\tbinom{6}{2}\,
(26?)=15条直线,其中包含3条平行于x轴(包含x轴)的直线,2条平行于y轴(包含y轴)的直线。为了保证直线不重复,从第0个点(原点(0,0))出发,走过的点不再走一遍,每个点都与剩下的点连接。他们分别是
点1 | 点2 | 直线方程 | 直线方程(一般形式) | A | B | C | value |
---|
(0,0) | (0,1) | x = 0 | 1x + 0y +0 =0 | 1 | 0 | 0 | y轴 | (0,0) | (0,2) | x = 0 | 1x + 0y +0 = 0 | 1 | 0 | 0 | y轴 | (0,0) | (1,0) | y = 0 | 0x + 1y + 0 = 0 | 0 | 1 | 0 | x轴 | (0,0) | (1,1) | y = x | (-1)x+1y + 0 =0 | -1 | 1 | 0 | 1 | (0,0) | (1,2) | y = -2x | (-2)x +1y+ 0=0 | -2 | 1 | 0 | 2 | (0,1) | (0,2) | x = 0 | 1x + 0y + 0 = 0 | 1 | 0 | 0 | y轴 | (0,1) | (1,0) | y =- x+1 | 1x + 1y+(-1)= 0 | 1 | 1 | -1 | 3 | (0,1) | (1,1) | y = 1 | 0x + 1y +(-1)=0 | 0 | 1 | -1 | 平行于x轴 | (0,1) | (1,2) | y = x+1 | (-1)x+1y+(-1)=0 | -1 | 1 | -1 | 4 | (0,2) | (1,0) | y = -2x+2 | 2x + 1y +(-2) = 0 | 2 | 1 | -2 | 5 | (0,2) | (1,1) | y = -x+2 | 1x + 1y +(-2) = 0 | 1 | 1 | -2 | 6 | (0,2) | (1,2) | y =2 | 0x + 1y +(-2)=0 | 0 | 1 | -2 | 平行于x轴 | (1,0) | (1,1) | x = 1 | 1x +0y +(-1)= 0 | 1 | 0 | -1 | 平行于y轴 | (1,0) | (1,2) | x = 1 | 1x +0y +(-1)= 0 | 1 | 0 | -1 | 平行于y轴 | (1,1) | (1,2) | x = 1 | 1x +0y+(-1)= 0 | 1 | 0 | -1 | 平行于y轴 |
所以点集{(x,y)|0≤x<2,0≤y<3,x ? Z,y ? Z}所连接起来的直线有 6+2+3 = 11 条;
??二、同理,对于再平面直角坐标系统XOY中,点集{(x,y)|0≤x<20,0≤y<21,x ? Z,y ? Z},可以确定20×21=420个点。420个点能确定
(
420
2
)
=
87990
?
\tbinom{420}{2}=87990\,
(2420?)=87990条直线。 ??使用C语言编写程序,用结构体STOP存储点的坐标,用结构体LINE存储直线的四个元素,A,B,C,value,其中value的值用来去重。STOP定义的结构体数组长度是col×row,结构体LINE定义的结构体数据长度可以假设为100000。 1、计算直线方程的方法: ???根据数学平面几何知识,两点确定一条直线,两点式直线方程表达式为:
?
(
y
?
y
1
)
/
(
y
1
?
y
2
)
=
(
x
?
x
1
)
/
(
x
1
?
x
2
)
?
\ (y-y_{1})/(y_{1}-y_{2}) = (x-x_{1})/(x_{1}-x_{2}) \,
?(y?y1?)/(y1??y2?)=(x?x1?)/(x1??x2?) ???变形后
?
(
y
?
y
1
)
(
x
1
?
x
2
)
=
(
x
?
x
1
)
(
y
1
?
y
2
)
?
\ (y-y_1)(x_1-x_2) = (x-x_1)(y_1-y_2) \,
?(y?y1?)(x1??x2?)=(x?x1?)(y1??y2?) ???再去括弧,移项,得一般形式方程:
?
(
y
1
?
y
2
)
x
+
(
?
(
x
1
?
x
2
)
)
y
+
(
x
1
?
y
2
?
y
1
?
x
2
)
=
0
?
\ (y_1-y_2 )x+(-(x_1-x_2 ))y+(x_1*y_2-y_1*x_2) =0 \,
?(y1??y2?)x+(?(x1??x2?))y+(x1??y2??y1??x2?)=0 ???对应于一般式 Ax+By+C = 0 分别是:
?
A
=
y
1
?
y
2
,
B
=
?
(
x
1
?
x
2
)
=
x
2
?
x
1
,
C
=
x
1
?
y
2
?
y
1
?
x
2
?
\ A=y_1-y_2,B=-(x_1-x_2 )=x_2-x_1,C = x_1*y_2-y_1*x_2 \,
?A=y1??y2?,B=?(x1??x2?)=x2??x1?,C=x1??y2??y1??x2? ???其中平行于x轴(包含x轴)直线和平行于y轴(包含y轴)直线,总和就是x轴和y轴上的点是的和,在计算直线方程时,不需要计算这种直线。 ???特别注意:需要对A,B,C约分,把 Ax+By+C = 0 化为最简形式,方便去重。
2、去重的方法: ??遍历直线LINE结构体数组,如果两个结构体中A,B,C数据相同,那么就认为这两个直线是重合的直线。第一条直线的不能判断它与哪条直线重合,那么把该直线的value数据赋值为1。从第二条直线开始,与它前面的所有直线作比较,如果前面有与该直线重合的直线,那么该直线的value数据不变,等于前一个直线的value数值;如果前面没有与该直线重合的直线,那么该直线的value数据将在前一个直线的value数值加1。遍历所有的直线后,最后一条直线的value值就是去重后的直线条数。 ??注意:最终的直线条数是 最后一条直线的value值 加上 平行于x轴(包含x轴)直线和平行于y轴(包含y轴)直线和。
#include<stdio.h>
#define max 1000000
#define row 21
#define col 20
struct SPOT
{
int x;
int y;
}spot[col*row];
struct LINE
{
int A;
int B;
int C;
int value;
}line[max];
int sum = 0;
int sczx(int,int,int,int);
int gcd(int,int);
int main()
{
int k,i,j;
k=0;
for(i=0;i<col;i++)
{
for(j=0;j<row;j++)
{
spot[k].x = i;
spot[k].y = j;
k++;
}
}
for(i=0;i<col*row;i++)
{
for(j=i+1;j<col*row;j++)
{
sczx(spot[i].x,spot[i].y,spot[j].x,spot[j].y);
}
}
for(i=1; i<sum; i++)
{
for(j=0; j<i; j++)
{
if( line[i].A == line[j].A && line[i].B == line[j].B && line[i].C == line[j].C )
{
line[i].value = line[i-1].value;
break;
}
line[i].value = line[i-1].value + 1;
}
}
printf("%d",line[sum-1].value + col + row);
return 0;
}
int sczx(int x1,int y1,int x2,int y2){
int A,B,C;
if(x1 == x2){ return 0; }
if(y1 == y2){ return 0; }
if(x1 != x2 && y1 !=y2){ A = y1-y2; B = x2-x1; C = x1*y2 - y1*x2; }
int fm;
if(C == 0){ fm = gcd(A,B);}
else{fm = gcd(gcd(A,B),C);}
line[sum].A = A/fm;
line[sum].B = B/fm;
line[sum].C = C/fm;
line[sum].value = 1;
sum++;
return 0;
}
int gcd(int m,int n){
if(m == 0 || n == 0) return 1;
if(m<0){ m = 0 - m; }
if(n<0){ n = 0 - n; }
if(m < n){
m = n - m;
n = n - m;
m = n + m;
}
int r = m % n;
while(r != 0)
{
m = n;
n = r;
r = m%n;
}
return n;
}
|