坐标旋转主要要找到参考系,对于一个坐标,我们需要维护它与参考系之间的角度及长度比。
坐标旋转公式
对于任意两个不同点A和B,A绕B旋转ang角度的坐标为:
(Δx∗cos(ang)−Δy∗sin(ang)+xB,Δy∗cos(ang)+Δx∗sin(ang)+yB) ( Δ x ∗ c o s ( a n g ) − Δ y ∗ s i n ( a n g ) + x B , Δ y ∗ c o s ( a n g ) + Δ x ∗ s i n ( a n g ) + y B )
B - Fractal
题意:操作一次就将该图中的所有线段按照比例变成所给的折线,这样操作d次,问从起点到一个点的长度为总长度的f倍,这个点的坐标是多少。
我们可以以折线的起点到终点的这条线段作为参考系,因为将一条线段变成需要的折线时,我们已知的就是起点和终点的坐标。再维护出每条折线段与参考系的角度及长度比。
计算时我们从后往前计算,维护一个剩余的长度即可。
#include
#include
#include
#include
#include
using namespace std;
const double eps=1e-8;
const int maxn=105;
int sgn(double x)
{
if(fabs(x)return 0;
if(x>0)return 1;
return -1;
}
struct Point
{
double x,y;
double ratio,ang;
Point(double sx,double sy){x=sx;y=sy;}
Point(){}
Point operator-(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
Point operator+(const Point &b)const
{
return Point(x+b.x,y+b.y);
}
Point operator/(const double b)const
{
return Point(x/b,y/b);
}
Point operator*(const double b)const
{
return Point(x*b,y*b);
}
double operator^(const Point &b)const
{
return x*b.y-y*b.x;
}
double operator*(const Point &b)const
{
return x*b.x+y*b.y;
}
void out()
{
cout<' '<typedef Point Vec;
Vec l[maxn];
double dis(Point a)
{
return sqrt(a.x*a.x+a.y*a.y);
}
double calc(Point a,Point b)
{
//a.out();
//b.out();
double tmp=(a.x*b.x+a.y*b.y)/(dis(a)*dis(b));
double tmp1= acos(tmp)*((a^b)>0?1:-1);
//cout<
//cout<
//double tmp2= atan2(b.y-a.y,b.x-a.x);
//cout<
//cout<
return tmp1;
}
Point rotate(Point a,double ang)
{
Point ans;
ans.x=a.x*cos(ang)-a.y*sin(ang);
ans.y=a.y*cos(ang)+a.x*sin(ang);
return ans;
}
int n,d;
double f;
double L;
double rate;
void go(Point s,double R,int dep,double theta,double ratio)
{
//cout<
for(int i=1;i//cout<<1<
double len=dis(l[i])*ratio*R;
//cout<
if(sgn(L-len)<=0)
{
//cout<<1<
if(dep)go(s,R/rate,dep-1,theta+l[i].ang,ratio*l[i].ratio);
else
{
s=s+rotate(l[i],theta)/dis(l[i])*L;
printf("(%.10f,%.10f)\n",s.x,s.y);
}
return;
}
else L-=len,s=s+rotate(l[i],theta)*ratio;
//s.out();
}
}
void solve()
{
double k=0;
double len=dis(p[n]-p[1]);
for(int i=1;i1 ]-p[i];
double tmpdis=dis(l[i]);
k+=tmpdis;
l[i].ratio=tmpdis/len;
l[i].ang=calc(p[n]-p[1],p[i+1]-p[i]);
}
rate=k/dis(p[n]-p[1]);
double R=1;
for(int i=1;i<=d;i++)R*=rate;
L=f*R*k;
//cout<
go(p[1],R,d,0,1);
}
int main()
{
//freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int x,y;
for(int i=1;i<=n;i++)
{
scanf("%d %d",&x,&y);
p[i]=Point(x,y);
}
scanf("%d %lf",&d,&f);
d--;
solve();
}
}
C - Stars
题意:给出星星的坐标,再给出星系的坐标,找出星普图中与星系相似的有多少个,并输出最大亮度的坐标。
首先我们可以枚举星普图中的两个点来对应星系的前两个点,这样就可以依次计算出后面的点,再一层for循环遍历一下在星普图中是否存在这个点。
这样计算的时间复杂度为n^3….,然而还是能过,博主实际想的是由于给的点都是整数点,我们可以依据这个首先可以判断出枚举的两个点是否符合题意,如果符合的话,在查找星普图是否存在这个点时,我们可以将坐标hash,或者放入set里面。这样时间复杂度就会减少了。
然而博主写的还是n^3..
#include
#include
#include
#include
#include
using namespace std;
const double eps =1e-9;
const double inf=1e9;
const int maxn=1005;
int sgn(double x)
{
if(fabs(x)return 0;
if(x>0)return 1;
return -1;
}
struct Point
{
double x,y;
double light;
Point(){}
Point(double sx,double sy):x(sx),y(sy){}
Point operator-(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
Point operator+(const Point &b)const
{
return Point(x+b.x,y+b.y);
}
Point operator/(const double b)const
{
return Point(x/b,y/b);
}
Point operator*(const double b)const
{
return Point(x*b,y*b);
}
double operator^(const Point &b)const
{
return x*b.y-y*b.x;
}
double operator*(const Point &b)const
{
return x*b.x+y*b.y;
}
void out()
{
cout<' '<char s[45];
int num;
void read()
{
scanf("%d %s",&num,s);
int x,y;
for(int i=1;i<=num;i++)
{
scanf("%d %d",&x,&y);
star[i]=Point(x,y);
}
}
Point temp[maxn],ans[maxn];
Point rotate(Point a,double ang)
{
Point res;
res.x=a.x*cos(ang)-a.y*sin(ang);
res.y=a.y*cos(ang)+a.x*sin(ang);
return res;
}
double dis(Point a)
{
return sqrt(a.x*a.x+a.y*a.y);
}
double calu(Point a,Point b)
{
return acos((a*b)/(dis(a)*dis(b)))*((a^b)>0?1:-1);
}
int n;
int check(Point a)
{
for(int i=1;i<=n;i++)
{
//p[i].out();
if(sgn(a.x-p[i].x)==0&&sgn(a.y-p[i].y)==0)return i;
}
return -1;
}
bool cmp(Point a,Point b)
{
if(sgn(a.x-b.x)!=0)return sgn(a.x-b.x)<0;
return sgn(a.y-b.y)<0;
}
int themaxlight;
Point themaxlightpoint;
bool check2(Point now)
{
for(int i=1;i<=num;i++)
{
if(sgn(star[i].x-now.x)==0&&sgn(star[i].y-now.y)==0)return 1;
}
return 0;
}
int solve2()
{
int res=0;
int m=num;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)if(i!=j)
{
int k;
for(k=3;k<=m;k++)
{
double ang=calu(star[2]-star[1],star[k]-star[1]);
double ratio=dis(star[k]-star[1])/dis(star[2]-star[1]);
Point now=star[i]+rotate(star[j]-star[i],ang)*ratio;
if(!check2(now))
break;
}
if(k==m+1)
res++;
}
return res;
}
void solve()
{
double anssum=-1;
int havenum=0;
int m=num;
if(m>n)
{
printf("%s occurs 0 time(s) in the map.\n",s);
return;
}
if(m==1)
{
printf("%s occurs %d time(s) in the map.\n",s,n);
printf("Brightest occurrence: (%d,%d)\n",(int)themaxlightpoint.x,(int)themaxlightpoint.y);
return;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)if(i!=j)
{
int k;
double sum=p[i].light+p[j].light;
for(k=3;k<=m;k++)
{
double ang=calu(star[2]-star[1],star[k]-star[1]);
double ratio=dis(star[k]-star[1])/dis(star[2]-star[1]);
Point now=p[i]+rotate(p[j]-p[i],ang)*ratio;
//now.out();
int idx=check(now);
if(idx!=-1)
{
//cout<
//cout<
temp[k]=p[idx];
sum+=p[idx].light;
}
else
break;
}
if(k==m+1)
{
havenum++;
if(anssum1 ]=p[i],ans[2]=p[j];
for(int t=3;t<=m;t++)
ans[t]=temp[t];
}
}
}
if(havenum==0)
{
printf("%s occurs 0 time(s) in the map.\n",s);
return;
}
int againnum=solve2();
printf("%s occurs %d time(s) in the map.\n",s,havenum/againnum);
sort(ans+1,ans+1+m,cmp);
printf("Brightest occurrence:");
for(int i=1;i<=m;i++)
printf(" (%d,%d)",(int)ans[i].x,(int)ans[i].y);
puts("");
}
int main()
{
//freopen("input.txt","r",stdin);
int cas=1;
while(~scanf("%d",&n)&&n)
{
themaxlight=-1;
int x,y,light;
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&x,&y,&light);
p[i]=Point(x,y);
p[i].light=light;
if(light>themaxlight)
{
themaxlight=light;
themaxlightpoint=p[i];
}
}
printf("Map #%d\n",cas++);
int m;
scanf("%d",&m);
while(m--)
{
read();
puts("");
solve();
}
puts("-----");
}
return 0;
}
D - Shade of Hallelujah Mountain
题意:在三维坐标系中,给出了一个平面,给出了一个凸多面体,再给出一个点光源。问凸多面体在平面中的阴影面积是多少。
按照hint的想法写就能过了,注意一些细节。特判一下a=0或者b=0的情况。
主要写起来真的让人不想写。。
#include
#include
#include
#include
#include
using namespace std;
const double eps=1e-9;
const double inf=1e9;
const int maxn=1005;
int sgn(double x)
{
if(fabs(x)return 0;
if(x>0)return 1;
return -1;
}
struct Point
{
double x,y;
Point(){}
Point(double sx,double sy):x(sx),y(sy){}
Point operator-(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
Point operator+(const Point &b)const
{
return Point(x+b.x,y+b.y);
}
Point operator/(const double b)const
{
return Point(x/b,y/b);
}
double operator^(const Point &b)const
{
return x*b.y-y*b.x;
}
double operator*(const Point &b)const
{
return x*b.x+y*b.y;
}
void out()
{
cout<' '<typedef pairdouble,double>,double>P3;
P3 p[maxn];
P3 sp;
double a,b,c,d;
Point p2[maxn];
double dis(Point a)
{
return sqrt(a.x*a.x+a.y*a.y);
}
bool cmp(Point a,Point b)
{
double tmp1=atan2(a.y-p2[1].y,a.x-p2[1].x);
double tmp2=atan2(b.y-p2[1].y,b.x-p2[1].x);
if(sgn(tmp1-tmp2)!=0)return sgn(tmp1-tmp2)<0;
return sgn(dis(a-p2[1])-dis(b-p2[1]))<0;
}
Point ans[maxn];
Point ch[maxn];
int n;
double Area(int num)
{
double res=0;
for(int i=2;i1])^(ch[i+1]-ch[1])/2;
}
return res;
}
void solve3()
{
for(int i=2;i<=n;i++)
{
if(sgn(p2[i].y-p2[1].y<0)||sgn(p2[i].y-p2[1].y)==0&&sgn(p2[i].x-p2[1].x)<0)
swap(p2[i],p2[1]);
}
sort(p2+2,p2+n+1,cmp);
int anum=0;
ch[1]=p2[1],ch[2]=p2[2],ch[3]=p2[3];
int top=3;
for(int i=4;i<=n;i++)
{
while(sgn((p2[i]-ch[top-1])^(ch[top]-ch[top-1]))>=0)top--;
ch[++top]=p2[i];
}
printf("%.2f\n",Area(top));
}
void solve2()
{
//cout<
int flag=0;
for(int i=1;i<=n;i++)
{
//cout<
if(sgn(sp.second-p[i].second)<=0)flag++;
}
if(flag==n)
puts("0.00");
else if(flag!=0)
puts("Infi");
else
{
for(int i=1;i<=n;i++)
{
double k=p[i].second/(sp.second-p[i].second);
double x=p[i].first.first-k*(sp.first.first-p[i].first.first);
double y=p[i].first.second-k*(sp.first.second-p[i].first.second);
p2[i]=Point(x,y);
//p2[i].out();
}
solve3();
}
}
double cal(Point a,Point b)
{
return acos((a*b)/(dis(a)*dis(b)))*((a^b)>0?1:-1);
}
Point rotate(Point a,double ang)
{
Point res;
res.x=a.x*cos(ang)-a.y*sin(ang);
res.y=a.y*cos(ang)+a.x*sin(ang);
return res;
}
double h[maxn];
double sh;
void init()
{
double dwn=sqrt(a*a+b*b+c*c);
for(int i=1;i<=n;i++)
{
double up=(p[i].first.first-d/a)*a+(p[i].first.second*b)+p[i].second*c;
h[i]=up/dwn;
//cout<
}
double up=(sp.first.first-d/a)*a+(sp.first.second*b)+sp.second*c;
sh=up/dwn;
}
void solve()
{
if(sgn(a)!=0||sgn(b)!=0)
{
init();
double ang=cal(Point(a,b),Point(0,sqrt(a*a+b*b)));
//cout<
//cout<
//cout<
for(int i=1;i<=n;i++)
{
Point temp;
temp.x=p[i].first.first;
temp.y=p[i].first.second;
temp=rotate(temp,ang);
p[i].first.first=temp.x,p[i].first.second=temp.y;
}
Point temp;
temp.x=sp.first.first;
temp.y=sp.first.second;
temp=rotate(temp,ang);
sp.first.first=temp.x,sp.first.second=temp.y;
//cout<
ang=cal(Point(sqrt(a*a+b*b),c),Point(0,sqrt(a*a+b*b+c*c)));
//cout<
for(int i=1;i<=n;i++)
{
temp.x=p[i].first.second;
temp.y=p[i].second;
temp=rotate(temp,ang);
p[i].first.second=temp.x,p[i].second=temp.y;
}
temp.x=sp.first.second;
temp.y=sp.second;
temp=rotate(temp,ang);
sp.first.second=temp.x,sp.second=temp.y;
for(int i=1;i<=n;i++)p[i].second=h[i];
sp.second=sh;
}
//for(int i=1;i<=n;i++)
//{
// cout<
//}
solve2();
}
int main()
{
//freopen("input.txt","r",stdin);
while(~scanf("%lf %lf %lf %lf",&a,&b,&c,&d))
{
//cout<<"********************************"<
if(a==0&&b==0&&c==0&&d==0)break;
scanf("%d",&n);
double x,y,z;
for(int i=1;i<=n;i++)
{
scanf("%lf %lf %lf",&x,&y,&z);
p[i].first=make_pair(x,y);
p[i].second=z;
}
double sx,sy,sz;
scanf("%lf %lf %lf",&sx,&sy,&sz);
sp.first=make_pair(sx,sy);
sp.second=sz;
solve();
}
return 0;
}
ALetter to Programmers
题意:现在有3种操作,平移,缩放,旋转,并且还有一个操作”重复”,它可以让它和命令end之间的操作重复x次。现在有n个点,问执行完这些操作后最后的点是多少。
真的好题啊,做的时候没想到怎么做,没想到是我们专业学习到的内容-仿射变换。
仿射变换的矩阵我会在另一篇博客介绍。
知道这个就好做了,只要计算出变换后的矩阵,那么就能一劳永逸了。
#include
#include
#include
#include
#include
using namespace std;
const double PI=acos(-1.0);
const double eps=1e-6;
struct M
{
int n,m;
double a[5][5];
M(int _n=0)
{
n=m=_n;
memset(a,0,sizeof(a));
}
M(int _n,int _m)
{
n=_n;
m=_m;
memset(a,0,sizeof(a));
}
void make_I(int _n)
{
n=m=_n;
memset(a,0,sizeof(a));
for(int i=1; i<=n; i++)a[i][i]=1;
}
friend M operator*(M a,M b)
{
M c(a.n,b.m);
for(int k=1; k<=a.m; k++)
for(int i=1; i<=a.n; i++)
for(int j=1; j<=b.m; j++)
c.a[i][j]+=a.a[i][k]*b.a[k][j];
return c;
}
void out()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
cout<' ';
cout<double x,double y,double z,double d)
{
M res(4);
double tmp=(1-cos(d))*x;
res.a[1][1]=tmp*x+cos(d),res.a[1][2]=tmp*y-sin(d)*z,res.a[1][3]=tmp*z+sin(d)*y;
tmp=(1-cos(d))*y;
res.a[2][1]=tmp*x+sin(d)*z,res.a[2][2]=tmp*y+cos(d),res.a[2][3]=tmp*z-sin(d)*x;
tmp=(1-cos(d))*z;
res.a[3][1]=tmp*x-sin(d)*y,res.a[3][2]=tmp*y+sin(d)*x,res.a[3][3]=tmp*z+cos(d);
res.a[4][4]=1;
return res;
}
M tran(double tx,double ty,double tz)
{
M res(4);
for(int i=1; i<=4; i++)res.a[i][i]=1;
res.a[1][4]=tx,res.a[2][4]=ty,res.a[3][4]=tz;
return res;
}
M sca(double a,double b,double c)
{
M res(4);
res.a[1][1]=a,res.a[2][2]=b,res.a[3][3]=c;
res.a[4][4]=1;
return res;
}
M quick_mul(int num,M a)
{
M res;
res.make_I(4);
while(num)
{
if(num%2)
res=res*a;
num/=2;
a=a*a;
}
return res;
}
M dfs(int num)
{
char s[20];
M res;
res.make_I(4);
while(~scanf("%s",s))
{
if(s[0]=='e')break;
if(s[0]=='r'&&s[1]=='o')
{
double a,b,c,d;
scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
d=d/180*PI;
double dis=sqrt(a*a+b*b+c*c);
a/=dis,b/=dis,c/=dis;
M tmp=Rotate(a,b,c,d);
res=tmp*res;
}
else if(s[0]=='r'&&s[1]=='e')
{
int times;
scanf("%d",×);
M tmp=dfs(times);
res=tmp*res;
}
else if(s[0]=='t')
{
double tx,ty,tz;
scanf("%lf %lf %lf",&tx,&ty,&tz);
M tmp=tran(tx,ty,tz);
res=tmp*res;
}
else if(s[0]=='s')
{
double a,b,c;
scanf("%lf %lf %lf",&a,&b,&c);
M tmp=sca(a,b,c);
//tmp.out();
res=tmp*res;
//res.out();
}
}
M ans=quick_mul(num,res);
return ans;
}
int main()
{
//freopen("input.txt","r",stdin);
int n;
while(~scanf("%d",&n)&&n)
{
M a;
a.make_I(4);
M ans=dfs(1);
//ans.out();
M p(4,1);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=3; j++)
scanf("%lf",&p.a[j][1]);
p.a[4][1]=1;
M theans;
theans=ans*p;
//theans.out();
printf("%.2f %.2f %.2f\n",theans.a[1][1]+eps,theans.a[2][1]+eps,theans.a[3][1]+eps);
}
puts("");
}
return 0;
}
总结:坐标旋转的题目都是好题,让人学习到了很多东西。