UVA 109 SCUD Busters【凸包模拟题】

题目大意:世界由几个互不重叠领土但彼此敌对的国家组成,每个国家有一个发电站,负责给本国发电。

                    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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值