這題寫出來超想放煙火慶祝的!學了Convex Hull、Graham Scan。生平第一次覺得外積是這麼有用、了不起兼神奇的發明(發現?)啊。只需要乘法,就可以找出兩個向量的角度關係,因此可以避免用到除法的機器浮點數問題,這實在是太神奇了。
一次AC,感動。不過是超嫩的Runtime 0.016,我確定單在sorting就有很大的進步空間。但能夠把一組一組零散的座標,讓電腦連成一個圖形,再算出面積,相當有成就感。
REFERENCES
Graham Scan
Computational Geometry (ppt)
CODE
#include <stdio.h> #define MAX_KINGDOM 20 #define MAX_VERTEX 100 int k, g[MAX_KINGDOM][MAX_VERTEX][2], gn[MAX_KINGDOM]; int findaim(int x, int y); int isinside(int kingdom, int x, int y); float findarea(int kingdom); int main(){ int i, j, s, tmp, min; int v, mx, my, at; int vx[MAX_VERTEX][2], attack[MAX_KINGDOM]; float tot; /*Kingdom data*/ v = 0; k = -1; while( scanf("%d", &v)!=EOF && v!=-1 ){ k++; for(i=0; i<v; i++) scanf("%d %d", &vx[i][0], &vx[i][1]); /*find lowest point; if more than one point are the lowest, find the most left one*/ min = 0; for(i=1; i<v; i++){ if( vx[i][1] < vx[min][1] ) min = i; else if( vx[i][1] == vx[min][1] ) if( vx[i][0] < vx[min][0] ) min = i; } if( min != 0 ){ tmp = vx[min][0]; vx[min][0] = vx[0][0]; vx[0][0] = tmp; tmp = vx[min][1]; vx[min][1] = vx[0][1]; vx[0][1] = tmp; } /*sort rest points by counter clockwise with outer product*/ for(i=1; i<v; i++){ min = i; for(j=(i+1); j<v; j++){ tmp = ( (vx[min][0]-vx[0][0])*(vx[j][1]-vx[0][1]) ) - ( (vx[j][0]-vx[0][0])*(vx[min][1]-vx[0][1]) ); if( tmp < 0 ) min = j; }/*j*/ if( min != i ){ tmp = vx[min][0]; vx[min][0] = vx[i][0]; vx[i][0] = tmp; tmp = vx[min][1]; vx[min][1] = vx[i][1]; vx[i][1] = tmp; } }/*i*/ /*Graham Scan*/ for(i=0; i<3; i++){ g[k][i][0] = vx[i][0]; g[k][i][1] = vx[i][1]; } s = 2; /*s: current stack*/ for(i; i<v; i++){ tmp = ( (g[k][s][0]-g[k][s-1][0])*(vx[i][1]-g[k][s-1][1]) ) - ( (vx[i][0]-g[k][s-1][0])*(g[k][s][1]-g[k][s-1][1]) ); if( tmp > 0 ){ s++; g[k][s][0] = vx[i][0]; g[k][s][1] = vx[i][1]; } else if( tmp == 0 ){ g[k][s][0] = vx[i][0]; g[k][s][1] = vx[i][1]; } else{ s--; i--; } } s++; g[k][s][0] = g[k][0][0]; g[k][s][1] = g[k][0][1]; gn[k] = s; }/*while kingdom data input*/ /*Missile attacks*/ while( scanf("%d %d", &mx, &my) != EOF ){ at = findaim(mx, my); if( at != -1 ) attack[at] = 1; }/*while missile attacks input*/ /*Output*/ tot = 0.0; for(i=0; i<=k; i++) if( attack[i] == 1 ) tot += findarea(i); printf("%.2f\n", tot); exit(0); } int findaim(int x, int y){ int i; for(i=0; i<=k; i++){ if( isinside(i, x, y) == 1 ) return i; }/*i: scan through all kingdoms*/ return -1; } int isinside(int kd, int x, int y){ int i, tmp; if( y < g[kd][0][1] ) return 0; for(i=0; i<gn[kd]; i++){ tmp = ( ( g[kd][i+1][0]-g[kd][i][0] )*( y-g[kd][i][1] ) ) - ( ( x-g[kd][i][0] )*( g[kd][i+1][1]-g[kd][i][1] ) ); if( tmp < 0 ) return 0; } return 1; } float findarea(int kd){ int i; float tmp, sum; sum = 0.0; for(i=1; i<=gn[kd]; i++){ tmp = ( (g[kd][i-1][0])*(g[kd][i][1]) )-( (g[kd][i][0])*(g[kd][i-1][1]) ); tmp /= 2; sum += tmp; } return sum; }
No comments:
Post a Comment