问题描述
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进 个单位长度。求传播单位
【输入】输入第一行包含一个正整数n(n<=30) ,表示宇宙射线会分裂n次
【输出】第二行包含n个正整数a1,a2……an ,第 i个数ai(ai<=5) 表示第 次分裂的宇宙射线会在它原方向上继续走多少个单位长度
【样例输入】
4
4 2 2 3
【样例输出】
39
问题分析
本题与图相关,基本与图相关的解法为bfs、dfs,此处选用dfs结构遍历
宇宙射线的结构是对称结构,因此只需要遍历一条完整的道路,不断对称得到其余结构就可解题
射线的行走方向总共有八个:沿x,y轴,y=x,y=-x,因此分情况讨论,从y轴正方向顺时针度旋转的法向量分别为(0,1) (1,1) (1,0) (1,-1) (0,-1) (-1,-1) (-1,0) (-1,1) 沿不同法向量行走的射线下一次分散的两个方向是确定的,选择其中一个发散方向,继续进行dfs递归,在每次进行递归时,提前使当前坐标点到达本次的发散终点 x2+=(a[temp]-1)*x1;
y2+=(a[temp]-1)*y1;
其中a【temp】-1是因为在进行dfs递归时,起点已经在第一格上,所以减一到达终点,dfs结束后遍历set容器中的元素,求对称点放入set中
在递归结束后,从终点倒回,依次放置发射沿途的单位格,最后set的不重复元素个数size即为所遍历单位长度
#include<iostream>
#include<set>
using namespace std;
int n,a[60];
struct point
{
int x,y;
bool operator<(const point & p)const
{
if(x!=p.x)return x<p.x;
if(y!=p.y)return y<p.y;
return false;
}
};
set <point> p;
void dfs(int x1,int y1,int x2,int y2,int temp)//x2,y2是坐标,x1y1是法向量
{
if(temp==n) return;
set <point> t;
set <point>::iterator it;
x2+=(a[temp]-1)*x1;//递归的时候已经在第一格上
y2+=(a[temp]-1)*y1;
if(x1==0&&y1==1)//沿y轴方向的
{
dfs(-1,1,x2-1,y2+1,temp+1); //取竖直的左边
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
q.x=2*x2-q.x;//对称公式,关于y轴对称
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(x1==0&&y1==-1)//沿y轴方向的
{
dfs(-1,-1,x2-1,y2-1,temp+1); //取竖直的左边
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
q.x=2*x2-q.x;//对称公式,关于y轴对称
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(y1==0&&x1==1)//沿x轴方向
{
dfs(1,-1,x2+1,y2-1,temp+1); // 取下边
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
q.y=2*y2-q.y;//对称公式
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(y1==0&&x1==-1)//沿x轴方向
{
dfs(-1,-1,x2-1,y2-1,temp+1); // 取下边
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
q.y=2*y2-q.y;//对称公式
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(x1==1&&y1==1)//y=x正方向第一象限
{
dfs(0,1,x2,y2+1,temp+1);//沿x轴向上
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
point q1=q;
q.x=q1.y-y2+x2;//对称公式
q.y=q1.x+y2-x2;
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(x1==1&&y1==-1)//第四象限
{
dfs(0,-1,x2,y2-1,temp+1);
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
point q1=q;
q.x=y2+x2-q1.y;//对称公式
q.y=x2+y2-q1.x;
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(x1==-1&&y1==-1)//第三象限
{
dfs(0,-1,x2,y2-1,temp+1);
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
point q1=q;
q.x=q1.y-y2+x2;//对称公式
q.y=q1.x+y2-x2;
t.insert(q);
}
p.insert(t.begin(),t.end());
}
if(x1==-1&&y1==1)//第二象限
{
dfs(0,1,x2,y2+1,temp+1);
for(it=p.begin();it!=p.end();it++)
{
point q=*it;
point q1=q;
q.x=y2+x2-q1.y;//对称公式
q.y=x2+y2-q1.x;
t.insert(q);
}
p.insert(t.begin(),t.end());
}
point m;
for(int i=0;i<=a[temp]-1;i++)
{
m.x=x2-i*x1;
m.y=y2-i*y1;
p.insert(m);
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
dfs(0,1,0,0,0);
cout<<p.size()<<endl;
}
尤其注意点(含出错点)
关于set
C++ STL set结构
关于在set结构中使用自定义结构体
1、自定义的结构体中初始未考虑x,y相等时返回false的情况导致set去重功能失败,程序运行错误
2、在结构体中自定义的重载函数不加const可能会报错
C++ STL常用结构
set、list、map区别与联系