--- title: 'Compute Area of Rectangle' tags: Coding Practice --- # Compute Area of Rectangle contributed by < `ChongMingWei` > ## Outline [TOC] ## 題目 給定一含有4個座標點的字串,坐標皆位於 Cartesian grid 上(皆為整數坐標點),給定的順序不為一定,請計算出該矩形的面積。 E.g. - input `{"(-1 2)","(4 -1)", "(4 2)", "(-1 -1)"}` - output `15` ## 實作流程 - 首先需要將給定的字串中,所有的座標資料分析出來,使用到 `strtok` 來切出數字的部分,接著使用 `strtol` 來將切出的數字字串轉變為 `long` 的資料型太後,映射到 `int` 資料型態儲存。 這邊我們只需要選擇前三組座標即可,原因如下: - 我們使用三組座標,會形成一個直角三角形,而我們可以藉由此三組座標得到三個不同的向量,其中必定會有兩個向量互相垂直,只要得到這兩個向量,就可以用外積來計算矩形面積。 ![](https://i.imgur.com/g77siqx.png) > 參考 [外積公式](https://read01.com/zh-tw/EQjg88.html#.X39XLMIzaM9) - 計算面積: 使用外積的方式,但此處我們只有二維,但仍可已將其擴充到三維坐標: $v1 = (x1,y1),\ v2=(x2,y2)>>v1 = (x1,y1,0),\ v2=(x2,y2,0)$ ![](https://i.imgur.com/2X8Mbec.png) 此時我們只需要計算 $x1y1-x2y2$ ,最後將此外積結果加上絕對值 $|x1y1-x2y2|$ 就是我們要求的面積。 ## 程式碼 ```c= #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> typedef struct vector{ int x; int y; }vec; //使用外積來計算矩形面積 int compute_cross(vec v1, vec v2){ int area = (v1.x*v2.y-v2.x*v1.y); //取絕對值 int mask = area>>31; return (area + mask) ^ mask; } int compute_area(char **a, int len){ int *coords = malloc(sizeof(int)*(len-1)*2); const char *lp = "("; const char *rp = ")"; const char *s = " "; /*This kind is also ok * char lp[] = "("; char rp[] = ")"; char s[] = " ";*/ for (int i =0;i<len-1;i++){ char *first=NULL, *second=NULL;//分別用來放空格前、後的字串 char *buf; buf = malloc(sizeof(char)*(strlen(a[i])+1));//strlen得到的會是去到`\0`的長度,所以+1 strncpy(buf, a[i], strlen(a[i])+1); first = strtok(buf, s); second = strtok(NULL, s); //以'('來切割,這邊'('前沒有字串,會返回'('後的字串,也就是x坐標 char *num1 = strtok(first, lp); //string轉long,再映射成int coords[2*i] = strtol(num1,NULL,10); //以')'來切割,返回')'前的字串,也就是y坐標 char *num2 = strtok(second, rp); //string轉long,再映射成int coords[2*i+1] = strtol(num2,NULL,10); //釋放記憶體 free(buf); } //前三組座標形成的三個向量 vec v1, v2, v3; v1.x = coords[2]-coords[0]; v1.y = coords[3]-coords[1]; v2.x = coords[4]-coords[0]; v2.y = coords[5]-coords[1]; v3.x = coords[4]-coords[2]; v3.y = coords[5]-coords[3]; //分別計算內積,若為0表示夾角為90度,使用外積計算面積並返回 if ((v1.x*v2.x+v1.y*v2.y)==0) return compute_cross(v1,v2); else if((v1.x*v3.x+v1.y*v3.y)==0) return compute_cross(v1,v3); else return compute_cross(v2,v3); //釋放記憶體 free(coords); } int main(int argc, char *argv){ char *a[] = {"(-1 2)","(4 -1)", "(4 2)", "(-1 -1)"}; int len = sizeof(a) / sizeof(*a); int area = compute_area(a,len); printf("result:%d\n",area); return 0; } ``` ### strtok的使用 當我們在使用 `strtok` 時,欲分割的字串必須要"可修改",因為欲分割的字串本身會遭到 `strtok` 修改,如以下範例: ```c= int main(int argc, char *argv){ char s[] = " "; char test[] = "(4 -1)"; char *buf = malloc(sizeof(test)); strcpy(buf,test); printf("%s\n",buf); char *first = strtok(buf, s); printf("%s\n",buf); char *first2 = strtok(NULL, s); printf("%s\n",buf); printf("%s\n",first); printf("%s\n",first2); return 0; } ``` 輸出結果: ```cpp (4 -1) //原本的 buf (4 //經過strtok處理過後的buf (4 (4 //first -1) //first2 ``` 如果改成以下: ```c= int main(int argc, char *argv){ char s[] = " "; char *buf = "(4 -1)";//內容不可被修改 printf("%s\n",buf); char *first = strtok(buf, s); printf("%s\n",buf); char *first2 = strtok(NULL, s); printf("%s\n",buf); printf("%s\n",first); printf("%s\n",first2); return 0; } ``` 輸出結果: ```cpp 執行期間發生錯誤(RE) #stdin #stdout 0s 4176KB ```