zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:走格子(模拟+BFS+Dijkstra)

    题目描述

    $CYJ$想找到他的小伙伴$FPJ$,$CYJ$和$FPJ$现在位于一个房间里,这个房间的布置可以看成一个$N$行$M$列的矩阵,矩阵内的每一个元素会是下列情况中的一种:
    $1.$障碍区域—这里有一堵墙(用$'#'$表示)。
    $2.$这是$CYJ$最开始在的区域(用$'C'$表示)。
    $3.$这是$FPJ$在的区域(用$'F'$表示)。
    $4.$空区域(用$'.'$表示)。
    $CYJ$携带了一个所谓传送枪的东西,这是一把可以创造传送门的枪械,在每一次行动中,他可以选择下列操作中的一项:
    $1.$移向一个相邻的格子中(上,下,左,右,不能移到墙在的格子里)。这个操作要消耗一个单位的时间。
    $2.$转向一个墙(不需要相邻,只需面向即可),向其发射传送门,传送门会留在墙内面向你的地方(至多只能同时存在两扇传送门),若墙上已经有两扇传送门,而你发射了第三扇,那么最初发射的那一扇会消失。同时,你无法在一个位置制造两扇传送门(这个操作不会耗费时间)。
    $3.$如果他与一块墙壁相邻且面前有一扇传送门,那么他可以移动到另一扇传送门前方的格子。这个操作会耗费一个单位的时间。
    $CYJ$想要知道自己最少需要多少时间才能够从起点($'C'$)到达终点($'F'$)。
    请注意:我们保证地图边缘会是一圈墙壁且一定存在$'C'$,$'F'$。


    输入格式

    第一行输入两个正整数$N$和$M$,表示地图大小。
    接下来的$N$行每行一个长度为$M$的字符串,表示地形。


    输出格式

    你需要输出最少的到达终点的时间,如果不能到达请输出$"no"$。


    样例

    样例输入1:

    4 4
    ####
    #.F#
    #C.#
    ####

    样例输出1:

    2

    样例输入2:

    6 8
    ########
    #.##..F#
    #C.##..#
    #..#...#
    #.....##
    ########

    样例输入2:

    4

    样例输入3:

    4 5
    #####
    #C#.#
    ###F#
    #####

    样例输出3:

    no


    数据范围与提示

    $50\%$的数据满足:$4leqslant N,Mleqslant 15$;
    $100\%$的数据满足:$4leqslant N,Mleqslant 500$;


    题解

    这道题教练出的有些尴尬,我在个人简介中说过我在多个信竞队都混过,然后就有了这道题的故事。

    大概在半年前,$Akoasm$大神出了这道题,他想卖版权,我帮他审的这道题,然而就在半年后……

    顺便附一个$Akoasm$大神的链接:$mathfrak{Akoasm}$

    扯淡完了,言归正转。

    这道题应该是我审过的$Akoasm$大神出的最好的一道题了。

    题目很新颖,很难想到正解,好多人都想到的是爆搜+剪枝,至于少数几个人想到了正解。

    首先,我们通过$BFS$预处理出距离最近墙的距离,在预处理出上下左右的第一面墙前的格子在哪里,建图,在图上跑$Dijkstra$即可。

    就这么简单,主要是很难想得到。

    时间复杂度:$Theta(n imes mlog(n imes m))$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
    	int nxt;
    	int to;
    	int w;
    }e[2222222];
    int head[300000],cnt;
    int n,m;
    char ch[600];
    int st,ed;
    bool Map[600][600];
    int bs[600][600],u[600][600],d[600][600],l[600][600],r[600][600];
    bool vis[300000];
    int dis[300000];
    queue<pair<int,int> > que;
    priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
    void add(int x,int y,int w)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	e[cnt].w=w;
    	head[x]=cnt;
    }
    void insert(int x,int y,int w)
    {
    	if(Map[x][y]&&!bs[x][y])
    	{
    		bs[x][y]=w;
    		que.push(make_pair(x,y));
    	}
    }
    void pre_bfs()
    {
    	while(!que.empty())
    	{
    		pair<int,int> flag=que.front();
    		que.pop();
    		insert(flag.first-1,flag.second,bs[flag.first][flag.second]+1);
    		insert(flag.first,flag.second-1,bs[flag.first][flag.second]+1);
    		insert(flag.first+1,flag.second,bs[flag.first][flag.second]+1);
    		insert(flag.first,flag.second+1,bs[flag.first][flag.second]+1);
    	}
    }
    void pre_work()
    {
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(Map[i][j])
    			{
    				if(!Map[i][j-1])l[i][j]=(i-1)*m+j;
    				else l[i][j]=l[i][j-1];
    				if(!Map[i-1][j])u[i][j]=(i-1)*m+j;
    				else u[i][j]=u[i-1][j];
    			}
    	for(int i=n;i;i--)
    		for(int j=m;j;j--)
    			if(Map[i][j])
    			{
    				if(!Map[i][j+1])r[i][j]=(i-1)*m+j;
    				else r[i][j]=r[i][j+1];
    				if(!Map[i+1][j])d[i][j]=(i-1)*m+j;
    				else d[i][j]=d[i+1][j];
    			}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(Map[i][j])
    			{
    				if(Map[i][j+1]){add((i-1)*m+j,(i-1)*m+j+1,1);add((i-1)*m+j+1,(i-1)*m+j,1);}
    				if(Map[i+1][j]){add((i-1)*m+j,i*m+j,1);add(i*m+j,(i-1)*m+j,1);}
    				if(u[i][j]!=(i-1)*m+j)add((i-1)*m+j,u[i][j],bs[i][j]);
    				if(d[i][j]!=(i-1)*m+j)add((i-1)*m+j,d[i][j],bs[i][j]);
    				if(l[i][j]!=(i-1)*m+j)add((i-1)*m+j,l[i][j],bs[i][j]);
    				if(r[i][j]!=(i-1)*m+j)add((i-1)*m+j,r[i][j],bs[i][j]);
    			}
    }
    void Dij(int x)
    {
    	memset(dis,0x3f,sizeof(dis));
    	q.push(make_pair(0,x));
    	dis[x]=0;
    	while(!q.empty())
    	{
    		int flag=q.top().second;
    		q.pop();
    		if(vis[flag])continue;
    		vis[flag]=1;
    		for(int i=head[flag];i;i=e[i].nxt)
    			if(dis[e[i].to]>dis[flag]+e[i].w)
    			{
    				dis[e[i].to]=dis[flag]+e[i].w;
    				q.push(make_pair(dis[e[i].to],e[i].to));
    			}
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",ch+1);
    		for(int j=1;j<=m;j++)
    		{
    			if(ch[j]=='C')st=(i-1)*m+j;
    			if(ch[j]=='F')ed=(i-1)*m+j;
    			if(ch[j]=='#')que.push(make_pair(i,j));
    			if(ch[j]=='C'||ch[j]=='F'||ch[j]=='.')Map[i][j]=1;
    		}
    	}
    	pre_bfs();
    	pre_work();
    	Dij(st);
    	printf("%d",dis[ed]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    WPF样式之画刷结合样式
    年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)
    30分钟学会XAML
    spring注解之@Import注解的三种使用方式
    大白话讲解Spring的@bean注解
    SpringBoot中的五种对静态资源的映射规则
    Spring注解之@Autowired、@Qualifier、@Resource、@Value
    Spring中如何使用工厂模式实现程序解耦?
    Spring注解之@Component、@Controller、@Service、@Repository
    Spring整合Redis
  • 原文地址:https://www.cnblogs.com/wzc521/p/11320354.html
Copyright © 2011-2022 走看看