1. 程式人生 > 其它 >試題 B: 直線 【第十二屆藍橋杯省賽 C/C++大學 A 組 第一場】

試題 B: 直線 【第十二屆藍橋杯省賽 C/C++大學 A 組 第一場】

試題 B: 直線

本題總分:5 分
【問題描述】
在平面直角座標系中,兩點可以確定一條直線。如果有多點在一條直線上,那麼這些點中任意兩點確定的直線是同一條。

給定平面上 2 × 3 個整點 {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即橫座標是 0 到 1 (包含 0 和 1) 之間的整數、縱座標是 0 到 2 (包含 0 和 2) 之間的整數的點。這些點一共確定了 11 條不同的直線。

給定平面上 20 × 21 個整點 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即橫座標是 0 到 19 (包含 0 和 19) 之間的整數、縱座標是 0 到 20 (包含 0 和 20) 之

間的整數的點。請問這些點一共確定了多少條不同的直線。

【答案提交】

這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。

 

思路:

直線的一般式:ax+by+c=0 。因為兩點能確定一條直線,故利用兩層迴圈,讓所有點兩兩連線構成直線,並在fun函式中判重(一條直線由一般式中的a,b,c三個引數確定,可利用一個三維陣列儲存這些引數)。

如:bool m[3][4][5]=true,即表示直線3x+4y+5=0已經存在了。

 

細節問題:

1,陣列的下標不能是負數啊,引數如果是負數的話怎麼辦?

答:根據資料範圍,a,b都在-20到20之間,c在-19*20到19*20=380之間,那我們記錄的時候只需要給這三個引數都加上一個定值,能讓最小的負數也能成正數就行了。

如:bool m[-3+50][4+50][-5+500]=true,即表示直線-3x+4y-5=0已經存在了。

 

2,怎麼化簡直線方程?

答:每個引數都除以(a,b,c)三個引數的絕對值 的最大公約數,用__gcd(abs(a),__gcd(abs(b),abs(c))即可

 

3,比如-2x+y+1=0和2x-y-1=0都是最簡直線方程,如何判重?

答:其實很好判重,只是容易漏掉這個細節.......

 

答案:40257

程式碼:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4
typedef double db; 5 #define rep(i,a,n) for (ll i=a;i<=n;i++) 6 #define per(i,a,n) for (ll i=n;i>=a;i--) 7 #define Y 20 8 #define X 19 9 const int MAXN = 1e5 + 10; 10 const int INF = 0x3f3f3f; 11 12 bool m[100][100][1000]; 13 14 struct node{ 15 int x,y; 16 }p[MAXN]; 17 18 void fun(int x1,int y1,int x2,int y2){ 19 int a=y2-y1; 20 int b=x1-x2; 21 int c=y1*x2-x1*y2; 22 int t=__gcd(abs(a),__gcd(abs(b),abs(c))); 23 //t是這三個引數的最大公約數 24 a=a/t+50; 25 b=b/t+50; 26 c=c/t+500; 27 //設定一個定值,防止陣列下標出現負數 28 if (!m[100-a][100-b][1000-c]) 29 //最簡方程判重 30 m[a][b][c]=true; 31 } 32 33 int main(){ 34 35 int n=0; 36 rep(i,0,Y){ 37 rep(j,0,X){ 38 ++n; 39 p[n].x=j; 40 p[n].y=i; 41 } 42 }//枚舉出所有的點,一共420個點 43 44 rep(i,1,n){ 45 rep(j,1,n){ 46 if(j!=i){ 47 int x1=p[i].x , y1=p[i].y; 48 int x2=p[j].x , y2=p[j].y; 49 fun(x1,y1,x2,y2); 50 //直線判重 51 } 52 } 53 }//讓所有點兩兩連線成直線 54 55 ll sum=0;//記錄所有不重複的直線 的數量 56 rep(i,0,99){ 57 rep(j,0,99){ 58 rep(k,0,999){ 59 if (m[i][j][k]) sum++; 60 } 61 } 62 } 63 cout<<sum; 64 return 0; 65 }

後記:

雖然程式碼不是最簡單的,但自認為是最簡單樸素的思路,絕對人人都能理解(沾沾自喜)