HDU 4793
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4793
题意:给一个以(0,0)为圆心半径为R的圆形区域,中间放着一个(0,0)为圆心半径为Rm的圆盘,在坐标(x,y)处(严格在圆形区域外)放着一枚半径为r的硬币,运动方向和速度为(vx,vy),在运动中碰到圆盘时,会按碰撞问题反弹(圆盘是固定不动的),问硬币会在圆形区域里呆多长时间(硬币只要有一点点在圆形区域里就记为硬币在圆形区域内)。
思路:首先先计算出硬币在移动过程中如果不与圆盘相撞,离圆心的最短距离h(如果硬币离圆心越来越远则不可能进入圆形区域)可以用余弦定理或者点到直线距离来求,找到的这个点恰巧是硬币在圆内运行轨迹的中点,如果不与圆盘碰撞,在圆内运行距离就可以用勾股定理求得(勾股弦分别为h,所求距离,圆域半径+硬币半径的直角三角形),如果与圆盘碰撞,那距离就要减去一段距离,也可以用勾股定理求得(勾股弦分别为h,所求距离,圆盘半径+硬币半径的直角三角形),因为硬币在圆域的运行过程是对称的,所以相减得到的距离恰为硬币在圆域内移动距离的一半,即可求得距离,时间。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <ctype.h>
#include <algorithm>
#include <string>
#include <set>
#define PI acos(-1.0)
#define maxn 100005
#define INF 0x7fffffff
#define eps 1e-8
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
int cmp(double x)
{
if(fabs(x)<eps)
return 0;
if(x>0)
return 1;
return -1;
}
inline int sgn(double n)
{
return fabs(n)<eps?0:(n<0?-1:1);
}
inline double sqr(double x)
{
return x*x;
}
struct point//点
{
double x,y;
point() {}
point(double a,double b):x(a),y(b) {}
void input()
{
scanf("%lf%lf",&x,&y);
}
friend point operator + (const point &a,const point &b)
{
return point(a.x+b.x,a.y+b.y);
}
friend point operator - (const point &a,const point &b)
{
return point(a.x-b.x,a.y-b.y);
}
friend bool operator == (const point &a,const point &b)
{
return cmp(a.x-b.x)==0 &&cmp(a.y-b.y)==0;
}
friend point operator * (const point &a,const double &b)
{
return point(a.x*b,a.y*b);
}
friend point operator * (const double &a,const point &b)
{
return point(a*b.x,a*b.y);
}
friend point operator / (const point &a,const double &b)
{
return point(a.x/b,a.y/b);
}
double norm()
{
return sqrt(sqr(x)+sqr(y));
}//到原点距离
void out () const
{
printf("%.2f %.2f",x,y);
}
};
double det (const point &a,const point &b)
{
return a.x*b.y-a.y*b.x;
}//叉积
double dot (const point &a,const point &b)
{
return a.x*b.x+a.y*b.y;
}//点乘
double dist (const point &a,const point &b)
{
return (a-b).norm();
}//距离
point rotate_point(const point &p,double A)
{
double tx=p.x,ty=p.y;
return point (tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A));
}//旋转,A是弧度
struct line
{
point a,b;
line() {}
line(point x,point y):a(x),b(y) {}
point dire()const
{
return b-a;
}//向量
double len()
{
return dire().norm();
}
};
bool parallel(line a,line b)
{
return !cmp(det(a.a-a.b,b.a-b.b));
}
bool line_make_point (line a,line b,point &res)
{
if(parallel(a,b))
return false;
double s1=det(a.a-b.a,b.b-b.a);
double s2=det(a.b-b.a,b.b-b.a);
res=(s1*a.b-s2*a.a)/(s1-s2);
return true;
}
int main()
{
double Rm,R,r,x,y,vx,vy;
while(~scanf("%lf%lf%lf%lf%lf%lf%lf",&Rm,&R,&r,&x,&y,&vx,&vy))
{
point a=point (x,y);
point b=point (x-vx,y-vy);
point e=point (vx,vy);
line l1=line(a,b);
point c=point (0,0);
point d=point (vy,-vx);
line l2=line(c,d);
point res;
line_make_point(l1,l2,res);
double h=res.norm();
double h1=R+r;
double h2=r+Rm;
double speed=sqrt(vx*vx+vy*vy);
if(dot(a,e)>=0)
printf("0.0000\n");
else if(h>=h1)
printf("0.0000\n");
else if(h>=h2)
printf("%.6lf\n",sqrt(h1*h1-h*h)/speed*2);
else printf("%.6lf\n",(sqrt(h1*h1-h*h)-sqrt(h2*h2-h*h))/speed*2);
}
return 0;
}
HDU 4798
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4798
题意:(真@阅读理解题)给出一个圆台,给出底部半径R和顶部半径r,圆台高度为H,把圆台分成F份登高的小圆台,按每个圆台顶部的圆为标准,用多边形(推得必须是正多边形来保证相切)来围住这些圆,这些多边形都是垂直的帘子,并且给出每个帘子的最小面积S,所以有它们的面积,它们的面积就是它们的耗费。问要求的最小耗费是多少。
思路:所求多边形周长为,θ是多边形一个端点和圆心的连线与圆心和这条边中点连线的夹角。θ越大消耗越大,即边数越少,消耗越大。
对于每层,根据最小面积S得到最小边长x,得到可以得到的多边形的边数的最大值,然后算出周长即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <ctype.h>
#include <algorithm>
#include <string>
#include <set>
#define PI acos(-1.0)
#define maxn 10005
#define INF 0x7fffffff
#define eps 1e-8
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
int main()
{
double R,r,H,S;int F;
while(~scanf("%lf%lf%lf%d%lf",&R,&r,&H,&F,&S))
{
double ans=0;
double c=(R-r)/F;
double h=H/F;
double l=S/h;
for(int i=0;i<F;i++)
{
double rr=r+i*c;
int tt=(int)(PI/(atan(l/(2*rr))));
double ss=rr*tan(PI/(1*tt));
ans+=ss*2*h*tt;
}
printf("%.3lf\n",ans);
}
return 0;
}