UVA 11373 Happy Birthday【计算/解析几何综合】

题目大意:对于蛋糕(圆柱体),切两刀(分别给出两点,确定一刀所在直线),分成四块蛋糕,求出最大蛋糕和最小蛋糕的体积。

                    切刀的交点不一定是蛋糕圆心,确定每一刀方向的两点也不一定在圆上;

解题策略:见代码注释。

小        结: 

                    题整体难度不大,综合性较强(直线相交,圆与直线相交,扇形面积,三角形面积等);

                    这道题做完要开始复习了,深深感觉到

        “Top-Down”编程风格或者说是编程思想的重要性,整体把握,模块实现,

                    调试,可读性都会成倍提升,努力培养自己良好的编程风格,或许这就是Mr.Zhu所说的看不见的东西吧!

/*
   UVA 11373 Happy Birthday
   AC by J_Dark
   Time 0.015s
   ON 2013/5/17
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <climits>
#include <vector>
#include <algorithm>
using namespace std;
const double eps = 1e-16;
const double PI = 3.141592653;

struct point{
	double x, y;
	point(double a=0, double b=0){ x = a; y = b; }
    double Distance(point t){
       return sqrt( (t.x-x)*(t.x-x) + (t.y-y)*(t.y-y) );
    }
	int Pos;
};
struct line{
	point u, v;
	line(point a, point b){ u = a; v = b; }
};
vector<point> LC; //记录直线与圆四个交点及两直线交点P
vector<line> L;  //记录切蛋糕两条直线以及由圆心与交点P确定的直线
double x10, y10, x11, y11, x20, y20, x21, y21, rad, height, MaxCake, MinCake;
point center(0,0);

void Input(){
	LC.clear();
	L.clear();
	L.push_back(line(point(x10, y10), point(x11, y11)));
	L.push_back(line(point(x20, y20), point(x21, y21)));
}

//计算直线与圆交点
void LC_InsectNode(line p){
	point t1, t2;
    if(fabs(p.u.x - p.v.x) < eps){
		t1.x = t2.x = p.u.x;
		t1.y = sqrt(rad*rad - t1.x*t1.x);
		t2.y = -t1.y;
		LC.push_back(t1);
		LC.push_back(t2);
	}
	else{
	    //将直线两点式转换为y=k*x+b形式,与圆方程x*x+y*y=r*r联立,求解交点
	    double k, b;
	    k = (p.u.y - p.v.y)/(p.u.x - p.v.x);
	    b = p.u.y - k*p.u.x;
		double mm = 4*k*k*b*b - 4*(k*k+1)*(b*b-rad*rad);
		t1.x = (-2*k*b + sqrt(mm)) / (2*(k*k+1));   //又是特么的计算式分母忘记加括号,结果特么wa那么久,擦擦擦……
		t2.x = (-2*k*b - sqrt(mm)) / (2*(k*k+1));
		t1.y = k*t1.x + b;
		t2.y = k*t2.x + b;
		LC.push_back(t1);
		LC.push_back(t2);
	}
}

//叉积计算三角形面积
double AreaTrangle(line a, line b){
	return fabs(( (a.v.x-a.u.x)*(b.v.y-b.u.y)-(b.v.x-b.u.x)*(a.v.y-a.u.y) )/2);
}

double Direction(point Pi, point Pj, point Pk){
	return (Pj.x-Pi.x)*(Pk.y-Pi.y)-(Pk.x-Pi.x)*(Pj.y-Pi.y);
}

//求两直线交点
void LL_InsectNode(line p, line q){
  double d1, d2, d3, d4;
  point t;
  d1 = Direction(p.u, p.v, q.u);
  d2 = Direction(p.u, p.v, q.v);
  d3 = Direction(q.u, q.v, p.u);
  d4 = Direction(q.u, q.v, p.v);
  t.x = (q.u.x*d2 - q.v.x*d1)/(d2 - d1);
  t.y = (q.u.y*d2 - q.v.y*d1)/(d2 - d1);
  LC.push_back(t);
}

//若q两端点在p同侧,返回true
bool isCross(line p, line q){
  double d1, d2, d3, d4;
  d1 = Direction(p.u, p.v, q.u);
  d2 = Direction(p.u, p.v, q.v);
  if(d1*d2>0)  return true;
  else return false;
}

/*
  “排序”:
  1,按照象限顺时针排序
  2,象限相同,叉积判断排序
*/ 
bool cmp(point a, point b){
   if(a.Pos == b.Pos){
      if(a.Pos == 1 || a.Pos == 4)  return a.y < b.y;
	  if(a.Pos == 2 || a.Pos == 3)  return a.y > b.y;
   }
   return a.Pos < b.Pos;
}
void Sort(){
	for(int i=0; i<LC.size(); i++){
		if(LC[i].x<=0 && LC[i].y>=0)   LC[i].Pos = 1;
		if(LC[i].x>0  && LC[i].y>=0)   LC[i].Pos = 2;
		if(LC[i].x<=0 && LC[i].y<0)    LC[i].Pos = 4;
		if(LC[i].x>0  && LC[i].y<0)    LC[i].Pos = 3;
	}
	sort(LC.begin(), LC.end(), cmp);
}

void Compute(){
    //计算两条直线与圆交点
	LC_InsectNode(L[0]); 
	LC_InsectNode(L[1]);
	//按照圆弧顺时针方向对交点排序
	Sort();
	//计算两条直线交点p
	LL_InsectNode(L[0], L[1]);  
	MaxCake = INT_MIN;
	MinCake = INT_MAX;
	double As, Ao, Ap, aa, bb, cc;
	L.push_back(line(LC[4], center));

    for(int i=0; i<4; i++){
		//余弦定理计算扇形圆心角
		aa = LC[i].Distance(center);
        bb = LC[(i+1)%4].Distance(center);
		cc = LC[i].Distance(LC[(i+1)%4]);
		double Angle = acos( (aa*aa+bb*bb-cc*cc)/(2*aa*bb) );
		Ao = AreaTrangle(line(center, LC[i]), line(center, LC[(i+1)%4]));
		Ap = AreaTrangle(line(LC[4], LC[i]), line(LC[4], LC[(i+1)%4]));
		
		line t(LC[i], LC[(i+1)%4]);
		double Ac;
        if(isCross(t, L[2])){
           //若在同侧,计算式如下
           As = Angle*rad*rad / 2;
           Ac = As - Ao + Ap;
        }
		else{
		   /*
		     若在异侧,还需判断角度是否钝角,
		     是——其所对弧应为优弧,圆心角为360减之
		     计算式如下
		   */
		   if((aa*aa+bb*bb-cc*cc)/(2*aa*bb) < eps) Angle = 2*PI - Angle;
		   As = Angle*rad*rad / 2;
		   Ac = As + Ao + Ap;
		} 
		MaxCake = max(MaxCake, Ac);
		MinCake = min(MinCake, Ac);
	}
}
void Output(){
	printf("%.2lf %.2lf\n", MaxCake*height, MinCake*height);
}
/
int main(){
	while(cin >> rad >> height >> x10 >> y10 >> x11 >> y11 >> x20 >> y20 >> x21 >> y21)
	{
		Input();
		Compute();
		Output();
	}
	//system("pause");
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值