UVA 109 SCUD Busters【凸包模擬題】
阿新 • • 發佈:2018-12-31
題目大意:世界由幾個互不重疊領土但彼此敵對的國家組成,每個國家有一個發電站,負責給本國發電。
1,給出每個國家的建築數(包括髮電站和房子數),每個國家用最少的圍牆將本國保護起來(凸包);
2,現在有不定數量的飛毛腿導彈開始襲擊這些國家,給出導彈落地點,落在某國區域內,某國直接玩完,以該國面積為大小的區域不能發電;
3,求出最後所有不能發電區域的總面積;
解題策略:
演算法思路:求出每個國家的凸包並計算面積——導彈挨個判定在不在凸包內——若在,則累加當前凸包面積
注意:若某國家之前被導彈襲擊過,之後再被襲擊的話,面積只能算一次;
PS:這題臨睡前抱著試試的態度做了下,按照自己的理解,設計好資料結構和演算法,沒想到1A,時間已是2:00,爽爆了!!!有木有!!!
明天一早還要編譯原理,目測明天事情也比較多,苦逼了,速度睡覺!!!
/* UVA 109 SCUD Busters AC by J_Dark ON 2013/5/7 2:20 根本沒想到會1A啊!!!!!爽爆了!!!!!! Time 0.015s */ #include <iostream> #include <cstdio> #include <algorithm> #include <vector> using namespace std; const int maxn = 110; ///////////////////////////////////////// struct point{ double x, y; point(double a, double b){ x = a; y = b; } }; struct Kingdom{ double area; bool use; int top; vector<int> CH; Kingdom(){ area = 0; top = 1; CH.clear(); CH.resize(maxn); CH[0] = 0; CH[1] = 1; use = false; //未被導彈襲擊 } }; vector<point> P, M; //臨時點集 導彈 vector< vector<point> > kdNode; //記錄國家點的資訊 vector<Kingdom> KD; //國家 int nodeNum; double ansArea=0; //不能發電區域面積 ///////////////////////////////////////// void Input(){ P.clear(); //M.clear(); //CH.clear(); double xx, yy; if(nodeNum != -1){ for(int i=0; i<nodeNum; i++){ cin >> xx >> yy; P.push_back(point(xx, yy)); } kdNode.push_back(P); } else{ while(cin >> xx >> yy) M.push_back(point(xx, yy)); } } //求凸包 bool cmp(point a, point b){ if(a.y == b.y) return a.x < b.x; return a.y < b.y; } //判斷向量p2-pp是否在向量p1-p2右側 bool turnRight(point p1, point p2, point pp){ const double eps = 1e-20; if((p2.x - p1.x)*(pp.y - p2.y) - (pp.x - p2.x)*(p2.y - p1.y) <= eps) return true; return false; } //計算叉積 double multi(point p0, point p1, point p2){ return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y); } void Compute(){ //計算每個國家的凸包 //cout << kdNode.size() << endl << endl; for(int k=0; k<kdNode.size(); k++){ sort(kdNode[k].begin(), kdNode[k].end(), cmp); KD.push_back(Kingdom()); //從起點0到到排序最後點作凸包右鏈 過程1 for(int i=2; i<kdNode[k].size(); i++){ while( KD[k].top && turnRight(kdNode[k][KD[k].CH[KD[k].top-1]], kdNode[k][KD[k].CH[KD[k].top]], kdNode[k][i]) ) { KD[k].top--; } KD[k].CH[++KD[k].top] = i; } int len = KD[k].top; //從排序最高點到到起點0fab反向作凸包右鏈 過程2 KD[k].CH[++KD[k].top] = kdNode[k].size()-2; for(int i=kdNode[k].size()-3; i>=0; i--){ //KD[k].top!=len, 不考慮已在過程1生成凸包上的點 while( KD[k].top!=len && turnRight(kdNode[k][KD[k].CH[KD[k].top-1]], kdNode[k][KD[k].CH[KD[k].top]], kdNode[k][i]) ) { KD[k].top--; } KD[k].CH[++KD[k].top] = i; } //計算每個國家凸包面積 for(int i=1; i<KD[k].top-1; i++){ KD[k].area += multi(kdNode[k][KD[k].CH[0]], kdNode[k][KD[k].CH[i]], kdNode[k][KD[k].CH[i+1]]); } //printf("KD[%d].area = %lf\n", k, KD[k].area); //判斷導彈是否襲擊當前國家 for(int m=0; m<M.size(); m++){ if(KD[k].use) break; //該國家之前已被導彈摧毀 for(int i=0; i<KD[k].top-1; i++){ if(!turnRight(kdNode[k][KD[k].CH[i]], kdNode[k][KD[k].CH[(i+1)%KD[k].top]], M[m]))//若點M[m]在凸包邊左側 KD[k].use = true; //該國家可能會被襲擊 else{ KD[k].use = false; //點M[m]不在凸包內部,導彈無法襲擊 break; } } if(KD[k].use){ //該國家已被當前導彈摧毀 ansArea += KD[k].area; break; } } } printf("%.2lf\n", ansArea/2); //由於按方向分解凸包時,叉積計算為三角形有效面積2倍,故總和應除以2 } ///////////////////////////////////////// int main(){ while(cin >> nodeNum) { Input(); if(nodeNum == -1) Compute(); } return 0; }