程序设计思维与实践 CSP-M1 补题 (3/4/数据班) C - 可怕的宇宙射线

思路

这道题可以用8个方向的bfs来解决,首先为八个方向编号0-7,八个方向的变化量用dx[]、dy[]来存储,途中经过的点用set来存储(自动去重),记录这个点是否来过用一个<pair<int,int>, bool>类型的map来表示。,假设射线从(0,0)开始,初始方向为向上。
对于每一条射线,将它为分裂前经过的点都加入set中,在分裂的时候由于45度方向,所以会产生(l.flag+1)%8、(l.flag+7)%8两个方向的新的射线,并且分裂数加一,但是如果每次分裂的点都要入队的话,复杂度是指数级别的,肯定要tle,所以我们用map来判断一下新分裂的节点以前是否产生过,如果没有,标记为来过,并且入队,如果前面产生过,则将其舍弃,由于此题的数据特殊,所以会产生大量的重复节点,用map判断后可以极大地降低复杂度。

总结

这个题考试的时候脑抽了,直到八个方向可以用简单的公式考虑统一,但是就是想列八种情况,各种+1-1,把自己整晕了,最后是分裂的时候有一个方向错了,得了0分,不过当时也没有考虑过去重,所以肯定也过不了。感觉设计算法是一定要看一下复杂度。

代码

#include<iostream>
#include<stdio.h>
#include<string>
#include<queue>
#include<set>
#include<map>
using namespace std;

struct light
{
	int cnt;
	int flag;
	int x,y;
	light(int cnt_,int flag_,int a,int b)
	{
		cnt=cnt_;
		flag=flag_;
		x=a;
		y=b;
	}
	bool operator <(const light& b) const
	{
		if(cnt!=b.cnt) return cnt<b.cnt;
		else if(flag!=b.flag) return flag<b.flag;
		else if(x!=b.x) return x<b.x;
		else  return y<b.y;   
	 } 
	
	
};

void put(light a)
{
	cout<<a.flag<<"("<<a.x<<", "<<a.y<<") "<<endl;
}

int dx[]={0, 1, 1, 1, 0, -1, -1, -1};
int dy[]={1, 1, 0, -1, -1, -1, 0, 1};
int main()
{
	queue<light> q;
	queue<light> nextq;
	light ll(0,0,0,0);
	q.push(ll);
	
	set< pair<int,int> >s;
	
	s.insert(pair<int,int>(0,0));
	
	int n;
	cin>>n;
	int *dis=new int[n];
	for(int i=0;i<n;i++)
		scanf("%d",&dis[i]);
		
	map<light,bool> global;
	set<light> temp;
	bool stop=false;
	while(!stop)
	{
	stop=true;
	while(!q.empty())
	{
		light l=q.front();
		q.pop();
		
		for(int i=0;i<dis[l.cnt]-1;i++)
		{
			if(l.flag==0)
				s.insert(pair<int,int>(l.x,++l.y));
			else if(l.flag==1)
				s.insert(pair<int,int>(++l.x,++l.y));
			else if(l.flag==2)
				s.insert(pair<int,int>(++l.x,l.y));
			else if(l.flag==3)
				s.insert(pair<int,int>(++l.x,--l.y));
			else if(l.flag==4)
				s.insert(pair<int,int>(l.x,--l.y));
			else if(l.flag==5)
				s.insert(pair<int,int>(--l.x,--l.y));
				else if(l.flag==6)
				s.insert(pair<int,int>(--l.x,l.y));
			else if(l.flag==7)
				s.insert(pair<int,int>(--l.x,++l.y));
		
		}
		
		if(l.cnt<n-1)
		{
		
			light a(l.cnt+1,(l.flag+1)%8,l.x+dx[(l.flag+1)%8],l.y+dy[(l.flag+1)%8]),
				  b(l.cnt+1,(l.flag+7)%8,l.x+dx[(l.flag+7)%8],l.y+dy[(l.flag+7)%8]);
			
			if(global.find(a)==global.end())
			{
			
				global[a]==1;
				nextq.push(a);
				s.insert(pair<int,int>(a.x,a.y));
			}
			if(global.find(b)==global.end())
			{
			
				global[b]==1;
				nextq.push(b);
				s.insert(pair<int,int>(b.x,b.y));
			}		
			
		}
		
	
	}
	
	while(!nextq.empty())
	{
		q.push(nextq.front());
		nextq.pop();
		stop=false;
	}
			

	}
	cout<<s.size()<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值