宇宙射线--图论

问题描述

宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右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区别与联系

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值