• 洛谷 题解 P2937 【[USACO09JAN]激光电话Laserphones】


    看到这题,一下就想到了爆搜。(不过这题输入也是够坑的)

    单纯的搜索肯定是会超时的,所以这里需要考虑一些剪枝。

    我们令bin[i][j][k]为在第i行j列时,方向为k的最小镜子数,若当时的镜子数已大于或等于此记录,那么就不必要更新了

    否则往该点的四个方向进行更新:

    • 方向相同

    没必要放镜子了

    • 方向相反

    不存在这种可能,忽略(否则你的镜子要怎么放呢?)

    • 其他

    放一面镜子,更新方向

    BFS代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=100+10;
    char Map[MAXN][MAXN];
    int n,m;
    int bx,by,ex,ey;
    int dx[5]={0,0,1,0,-1};
    int dy[5]={0,1,0,-1,0};
    int ans=0x3f3f3f3f;
    int bin[MAXN][MAXN][5];//剪枝用
    struct Node
    {
    	int x,y;
    	int cnt;
    	int dir;//表示的方向
    	/*
    	1:right
    	2:down
    	3:left
    	4:up
    	*/
    };
    inline int read()
    {
    	int tot=0;
    	char c=getchar();
    	while(c<'0'||c>'9')
    		c=getchar();
    	while(c>='0'&&c<='9')
    	{
    		tot=tot*10+c-'0';
    		c=getchar();
    	}
    	return tot;
    }
    inline void BFS()
    {
    	queue<Node>q;
    	q.push((Node){bx,by,0,1});//推四种方向到队列中
    	q.push((Node){bx,by,0,2});
    	q.push((Node){bx,by,0,3});
    	q.push((Node){bx,by,0,4});
    	bin[bx][by][1]=bin[bx][by][2]=bin[bx][by][3]=bin[bx][by][4]=0;
    	while(q.size())
    	{
    		Node now=q.front();
    		//cout<<now.x<<" "<<now.y<<" "<<now.cnt<<" "<<now.dir<<endl;
    		q.pop();
    		if(now.cnt>=ans)continue;
    		if(now.x==ex&&now.y==ey)
    		{
    			ans=min(ans,now.cnt);//更新答案
    			continue;//注意:这里不能用break
    		}
    		for(int i=1;i<=4;i++)
    		{
    			int a=dx[i]+now.x,b=dy[i]+now.y;
    			if(a<1||b<1||a>n||b>m)continue;
    			if(now.cnt>=bin[a][b][i])continue;//没必要更新了
    			if(Map[a][b]=='*')continue;
    			if(now.dir==i)
    			{
    				q.push((Node){a,b,now.cnt,i});
    				bin[a][b][i]=now.cnt;//更新最小值
    			}
    			else 
    			{
    				if(now.dir+i==4)continue;//这是方向相反时,看不懂的回去看一下各个数字代表的方向
    				q.push((Node){a,b,now.cnt+1,i});
    				bin[a][b][i]=now.cnt+1;//更新最小值
    			}
    		}
    	}
    }
    int main()
    {
    	m=read();n=read();
    	memset(bin,0x3f3f3f3f,sizeof(bin));//赋初值
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=m;j++)
    		{
    			cin>>Map[i][j];
    			if(Map[i][j]=='C'&&!bx&&!by)bx=i,by=j;//寻找起点
    			else if(Map[i][j]=='C')ex=i,ey=j;//寻找终点
    		}
    	}
    	BFS();
    	/*for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=m;j++)
    		{
    			for(int k=1;k<=4;k++)cout<<bin[i][j][k]<<" ";
    			cout<<endl;
    		}
    		cout<<endl<<endl;
    	}*/
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    SpringBoot发送邮箱验证码
    判断一个数是否为2的整数次幂
    [模板] 虚树 && bzoj2286-[Sdoi2011]消耗战
    [模板] K-D Tree
    [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
    对于约数个数上界的估计
    luogu3702-[SDOI2017]序列计数
    [模板] 线性基
    [模板] 区间mex && 区间元素种数
    bzoj4367-[IOI2014]holiday假期
  • 原文地址:https://www.cnblogs.com/hulean/p/10801570.html
Copyright © 2020-2023  润新知