01迷宫-做题报告
01迷宫
2018-10-19
看到这道题就无脑bfs了,然后拿了50分。然而并不知道怎么优化。
#include<bits/stdc++.h>
using namespace std;
int n,m;
int mmp[5000][5000];
int x,y;
int vis[5000][5000];
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
int ans=0;
struct node{
int x,y;
};
queue<node> Q;
inline int bfs(int x,int y){
node s;
s.x=x,s.y=y;
Q.push(s);
vis[x][y]=1;
ans++;
while(!Q.empty()){
node k=Q.front();
Q.pop();
for(int i=0;i<4;i++){
node zzq;
int sx=k.x+dx[i],sy=k.y+dy[i];
//printf("sx=%d sy=%d\n",sx,sy);
if(sx<=n&&sx>=1&&sy<=n&&sy>=1&&!vis[sx][sy]&&mmp[sx][sy]!=mmp[k.x][k.y]){
//printf("SSR::sx=%d sy=%d\n",sx,sy);
vis[sx][sy]=1;
ans++;
zzq.x=sx,zzq.y=sy;
Q.push(zzq);
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c;
cin>>c;
mmp[i][j]=c-'0';
}
}
for(int i=1;i<=m;i++){
cin>>x>>y;
ans=0;
bfs(x,y);
memset(vis,0,sizeof vis);
cout<<ans<<endl;
}
return 0;
}
我觉得超时主要的原因是每次输入都要询问废话,还有每次都要用memset来清空vis数组(但是不知道要怎么改啊啊啊)
然后我看了很多篇题解,终于发现了一篇适合我的:
大概的思路是记忆化
-
设num为第num的次输入。则anser[num]就是第num次输入的答案
-
把原来用来标记的vis数组的赋值步骤vis[sx][sy]=1改成vis[sx][sy]=num;因为只要在bfs(x,y)中搜索到了sx,sy;那么根据题目的性质bfs(sx,sy)和bfs(x,y)的答案是一样的;记得在开头vis[x][y]=num
-
最后在每一次bfs的结尾把答案存入anser[num]中,下一次搜索时如果vis[x][y]有值那么直接输出anser[vis[x][y]]即可。
附上我的AC代码
#include<bits/stdc++.h> using namespace std; int n,m; int mmp[5000][5000]; int x,y; int vis[5000][5000]; int anser[5000000]; int dx[]={1,0,-1,0}; int dy[]={0,1,0,-1}; int ans=0; struct node{ int x,y; }; queue<node> Q; int num=0; inline void bfs(int x,int y){ ans=0; node s; num++; if(vis[x][y]){ cout<<anser[vis[x][y]]<<endl; return ; } s.x=x,s.y=y; Q.push(s); vis[x][y]=num; ans++; while(!Q.empty()){ node k=Q.front(); Q.pop(); for(int i=0;i<4;i++){ node zzq; int sx=k.x+dx[i],sy=k.y+dy[i]; //printf("sx=%d sy=%d\n",sx,sy); if(sx<=n&&sx>=1&&sy<=n&&sy>=1&&!vis[sx][sy]&&mmp[sx][sy]!=mmp[k.x][k.y]){ //printf("SSR::sx=%d sy=%d\n",sx,sy); ans++; vis[sx][sy]=num; zzq.x=sx,zzq.y=sy; Q.push(zzq); } } } anser[num]=ans; cout<<ans<<endl; return ; } int main(){ ios::sync_with_stdio(false); cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ char c; cin>>c; mmp[i][j]=c-'0'; } } for(int i=1;i<=m;i++){ cin>>x>>y; bfs(x,y); } return 0; }
现在是2018/12/06 我又重做了一遍这道题。
这次完全是自己的思想
我看了下样例发现了一个规律,你每次搜索时搜索到的每一个点的答案都是一样的,于是我每次dfs完直接把搜到的点的答案都更新一边就可以了。
$code$
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
using std::vector;
using std::pair;
using std::cin;
inline void read(int &x)
{
x=0;char ch=0;bool sign=false;
while(ch < '0' || ch > '9')
{
sign|=(ch == '-');
ch=getchar();
}
while(!(ch < '0' || ch > '9'))
{
x=x*10+(ch^48);
ch=getchar();
}
x=sign ? -x : x;
}
const int dx[4]={0,0,-1,1},
dy[4]={1,-1,0,0};
int n,m;
int x,y;
int dis[1220][1102];
char map[1300][1200];
int vis[1232][2323];
int p,k;
vector< pair<int , int> > ans;
inline void dfs(int x,int y)
{
//printf("map[%d][%d]=%d \n",x,y,map[x][y]);
if(dis[x][y] > 1){
return ;
}
for(int i=0; i<4; i++)
{
int sx=x+dx[i],sy=y+dy[i];
//printf("map[%d][%d]=%d \n",sx,sy,map[sx][sy]);
if(sx<1 || sx>n || sy<1 || sy>n || vis[sx][sy] || map[sx][sy] == map[x][y])continue;
vis[sx][sy]=1;
ans.push_back({sx,sy});
dfs(sx,sy);
dis[x][y]+=dis[sx][sy];
}
}
int main()
{
read(n);read(m);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
dis[i][j]=1;
cin>>map[i][j];
}
//getchar();
}
for(int i=1; i<=m; i++)
{
//memset(vis, 0 ,sizeof vis);
read(x),read(y);
/*if(dis[x][y] > 1)
{
printf("%d\n",dis[x][y]);
}
else
{*/
ans.clear();
vis[x][y]=1;
p=x,k=y;
dfs(x,y);
for(int i=0; i<ans.size(); i++)
{
//printf("x=%d y=%d ans[%d][%d]=%d\n",x,y,ans[i].first,ans[i].second,dis[x][y]);
dis[ans[i].first][ans[i].second]=std::max(dis[x][y],dis[ans[i].first][ans[i].second]);
}
printf("%d\n",dis[x][y]);
//}
}
return 0;
}
之前忘了每次询问都要ans.clear();了,然后还一度怀疑自己的做法是错的。。。