week4_csp模测_C 可怕的宇宙射线

题目概述

众所周知,瑞神已经达到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着一种叫做苟狗的生物,这种生物天生就能达到人类研究生的知识水平,并且天生擅长CSP,甚至有全国第一的水平!但最可怕的是,它可以发出宇宙射线!宇宙射线可以摧毁人的智商,进行降智打击!
宇宙射线会在无限的二维平面上传播(可以看做一个二维网格图),初始方向默认向上。宇宙射线会在发射出一段距离后分裂,向该方向的左右45°方向分裂出两条宇宙射线,同时威力不变!宇宙射线会分裂 次,每次分裂后会在分裂方向前进ai个单位长度。现在瑞神要带着他的小弟们挑战苟狗,但是瑞神不想让自己的智商降到普通本科生zjm那么菜的水平,所以瑞神来请求你帮他计算出共有多少个位置会被"降智打击"。

输入输出

Input

输入第一行包含一个正整数 n(n<=30),表示宇宙射线会分裂n 次
第二行包含n个正整数a1,a2···an ,第ai 个数(ai<=5)表示第 i次分裂的宇宙射线会在它原方向上继续走多少个单位长度

Output

输出一个数ans ,表示有多少个位置会被降智打击

Sample Input
4
4 2 2 3
Sample Output
39

思路分析

这道题csp模测的时候我没写到,结束后看到大佬在群里讨论说用dfs剪枝就行了,因此少走了一些弯路哈哈。
剪枝的实现是定义一个布尔类型的四维数组,利用对称的性质,同一个位置(x,y)同一层同方向是重复的只做一遍就行了。
对于是否走过某点用map.count(key)函数实现,没走过返回0,ans++,将该点加入map;走过则返回1。
具体看代码。

注意

注意起点坐标,是自己设定的,与judge数组中x y的范围匹配起来。因为最多30次分裂且每次分裂前最多走5步,因此若从中心发射,上下左右最多各需要150格,因此这里定义的四维数组的坐标x,y的范围均为400,起点坐标从(200,200)开始。

代码

#include<iostream>
#include<map>
using namespace std;

int n,ans=0;
int a[31];
//射线共8个方向:上、右上、右、右下、下、左下、左、左上 
int dx[]={0,1,1,1,0,-1,-1,-1};
int dy[]={1,1,0,-1,-1,-1,0,1};
bool judge[400][400][31][8]={false};
struct point{
  int x,y;
  bool operator<(const point &p)const{
      return x!=p.x? x<p.x:y<p.y;
  }
};
map<point,int> mp;

void solve(point p,int k,int flag)
{//k记录层数,flag记录当前射线的方向 
    if(k>=n) return;
    int x=p.x,
        y=p.y;
    if(judge[x][y][k][flag]) return;
    judge[x][y][k][flag]=true;
    for(int i=0;i<a[k];i++)
    {//每一层走指定的步数,每一步的方向都是flag 
        x+=dx[flag];
        y+=dy[flag];
        point p1;
        p1.x=x;
        p1.y=y;
        if(mp.count(p1)==0){
            //如果没走过该点 
            ans++;
            mp[p1]=1;
        }
     }
     point p2;
     p2.x=x;
     p2.y=y;
     //分别向左右45度方向分裂 
     solve(p2,k+1,(flag+7)%8);
     solve(p2,k+1,(flag+1)%8);
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    solve({200,200},0,0);
    cout<<ans<<endl;
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值