洛谷 P1141 01迷宫
题目分析:看网上的大佬们都说这道题普通的搜索和广搜都过不去,得要优化一下,有些大佬使用hash判重和并查集?(我是没有懂,我还是太菜了)然后就继续翻别人的博客,后面发现了两种很优美的算法,一种是深搜,一种是广搜。分别贴出来吧,其实这两位的都用到了差不多一样的优化,这种优化挺好的。(不要问我为什么都是贴的别人的,因为考试快来了,没那多时间了,所以主要是学学思路)
深搜代码(来自洛谷用户:囧人232)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int dx[4]={-1,0,1,0};
const int dy[4]={0,1,0,-1};
int g[1001][1001],f[1001][1001],d[1000005];//d数组就是在下的优化,每种颜色对应的答案
int n,m,k,ans,cnt=1;
string c;
void init(){ans=0;}
void dfs(int x,int y){
ans++; f[x][y]=cnt;
for(int i=0;i<4;++i) {
int xx=x+dx[i],yy=y+dy[i];
if(!f[xx][yy]&&1<=xx&&xx<=n&&1<=yy&&yy<=m&&(g[xx][yy]!=g[x][y])) dfs(xx,yy);
}
d[cnt]=ans;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
cin>>c; m=c.size();
for(int j=0;j<m;j++) g[i][j+1]=c[j]-'0';
}
for(int i=1;i<=k;i++){
init();
int a,b;
scanf("%d%d",&a,&b);
if(!f[a][b]){ dfs(a,b); cnt++; }
printf("%d\n",d[f[a][b]]);
}
return 0;
}
下面这种是广搜(Luogu P1141 01迷宫)
#include <cstdio>
using namespace std;
struct node {
int x,y,s;
}a[1000001];
char map[1001][1001];
int n,m,startx,starty,num,book[1001][1001],mark[1001][1001],ans[1000001];
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int bfs(int color){
int head=1,tail=2,tx,ty,k,sum=1;
mark[startx][starty]=color; book[startx][starty]=1;
a[head].x=startx;a[head].y=starty; a[head].s=0;
while(head<tail){
for(k=0;k<=4-1;k++){
tx=a[head].x+next[k][0]; ty=a[head].y+next[k][1];
if(tx<1 || tx>n || ty<1 || ty>n) continue;
if(map[tx][ty]!=map[a[head].x][a[head].y] && book[tx][ty]==0){
book[tx][ty]=1; mark[tx][ty]=color;
sum++;
a[tail].x=tx; a[tail].y=ty;
a[tail].s=a[head].s+1;
tail++;
}
}
head++;
}
return sum;
}
int main(){
num=1;
int i,j;
scanf("%d %d\n",&n,&m);
for(i=1;i<=n;i++){ gets(map[i]+1); }
for(i=1;i<=m;i++) {
scanf("%d %d",&startx,&starty);
if(mark[startx][starty]!=0) {
printf("%d\n",ans[mark[startx][starty]]);
}
else {
ans[num]=bfs(num);
printf("%d\n",ans[num]);
}
num++;
}
return 0;
}
不知为何当初的自己要发以上两篇博客,明明很简单的题目,发博客就算了,结果还是别人的,真是太菜了.
洛谷 P1363 幻想迷宫
题目描述
背景 Background
(喵星人LHX和WD同心协力击退了汪星人的入侵,不幸的是,汪星人撤退之前给它们制造了一片幻象迷宫。)
WD:呜呜,肿么办啊……
LHX:momo…我们一定能走出去的!
WD:嗯,+U+U!
描述 Description
幻象迷宫可以认为是无限大的,不过它由若干个N*M的矩阵重复组成。矩阵中有的地方是道路,用’.’表示;有的地方是墙,用’#’表示。LHX和WD所在的位置用’S’表示。也就是对于迷宫中的一个点(x,y),如果(x mod n,y mod m)是’.’或者’S’,那么这个地方是道路;如果(x mod n,y mod m)是’#’,那么这个地方是墙。LHX和WD可以向上下左右四个方向移动,当然不能移动到墙上。
请你告诉LHX和WD,它们能否走出幻象迷宫(如果它们能走到距离起点无限远处,就认为能走出去)。如果不能的话,LHX就只好启动城堡的毁灭程序了……当然不到万不得已,他不想这么做。。。
输入输出格式
输入格式:
输入格式 InputFormat
输入包含多组数据,以EOF结尾。
每组数据的第一行是两个整数N、M。
接下来是一个N*M的字符矩阵,表示迷宫里(0,0)到(n-1,m-1)这个矩阵单元。
输出格式:
输出格式 OutputFormat
对于每组数据,输出一个字符串,Yes或者No。
输入输出样例
输入样例#1
5 4
##.#
##S#
#..#
#.##
#..#
5 4
##.#
##S#
#..#
..#.
#.##
输出样例
Yes
No
说明
数据范围和注释 Hint
对于30%的数据,N,M<=20
对于50%的数据,N.M<=100.
对于100%的数据,N,M<=1500,每个测试点不超过10组数据.
题目分析
笼统的说,这道题就是要找一条路,可以无穷尽的走下去.也就是差不多走到某个点后,可以从这点回到原来的起点.可以看看这个大佬解释的:https://www.luogu.org/blog/GNAQ/solution-p1363
程序代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,sx,sy,dx[4]={0,-1,0,1},dy[4]={-1,0,1,0},ans=0;
int vis[1510][1510][3]={0};
bool map[1510][1510]={false};
void dfs(int x,int y,int xx,int yy) {
if(vis[xx][yy][2]&&(vis[xx][yy][0]!=x||vis[xx][yy][1]!=y)) {ans=1;return ;}//如果这个点走过,并且不完全是和上一个点相同,那就返回1
if(vis[xx][yy][2]&&vis[xx][yy][0]==x&&vis[xx][yy][1]==y) return ;//如果走到上一个点,那就回溯
vis[xx][yy][0]=x;vis[xx][yy][1]=y;vis[xx][yy][2]=1;//记录一下
register int x1,y1;
for(register int w=0;w<=3;++w){
x1=(xx+dx[w]+n)%n;y1=(yy+dy[w]+m)%m;
if(map[x1][y1]) dfs(x+dx[w],y+dy[w],x1,y1);
}
}
int main(){
char ch;
while(cin>>n>>m) {
memset(map,false,sizeof(map));
memset(vis,false,sizeof(vis));
ans=0;
for(register int i=0;i<n;++i)
for(register int j=0;j<m;++j){
cin>>ch;
if(ch=='.') map[i][j]=true;
else if(ch=='S') { sx=i;sy=j;map[i][j]=true;}
}
dfs(sx,sy,sx,sy);
if(ans) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}