目录
- P1141 01迷宫
- 我的思路
- 总结1:
- **大佬的思路**:
- 总结2:
- 1.[自加自减](https://www.cnblogs.com/pangxiaodong/archive/2011/08/09/2133053.html)
- 2.[C语言register关键字—最快的关键字](https://www.cnblogs.com/kingqinwang/p/5097335.html)
- 3.[std::ios::sync_with_stdio(false);](https://blog.csdn.net/weixin_51333606/article/details/116738816)
- 4.[C++中std的使用和作用](https://blog.csdn.net/baidu_37830419/article/details/79085312?utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control)
- 5.[inline内联函数的标记](https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html)
P1141 01迷宫
题目描述
有一个仅由数字00与11组成的n \times nn×n格迷宫。若你位于一格00上,那么你可以移动到相邻44格中的某一格11上,同样若你位于一格11上,那么你可以移动到相邻44格中的某一格00上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入格式
第11行为两个正整数n,mn,m。
下面nn行,每行nn个字符,字符只可能是00或者11,字符之间没有空格。
接下来mm行,每行22个用空格分隔的正整数i,ji,j,对应了迷宫中第ii行第jj列的一个格子,询问从这一格开始能移动到多少格。
输出格式
mm行,对于每个询问输出相应答案。
输入
2 2
01
10
1 1
2 2
输出
4
4
我的思路
拿道题,输入为迷宫类型的,故使用迷宫的做法,但是每次询问都要重新搜,故超时了。
注:这里maze一定要设置为char类型,若为int类型,会读不进去,因为俩数据之间没有空格,所以10会被看成一个数据,多磨痛的领悟(我不会告诉你我这个点卡了一个小时)
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int ,int > P;
const int MAX_N = 1005;
const int MAX_M = 100005;
int n,m;
char maze[MAX_N][MAX_N];
int g,h;
P p;
int d[MAX_N][MAX_N];
int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};
bool check(int x,int y)
{
return 1 <= x && x <= n && 1 <= y && y <= n;
}
int bfs()
{
int ans = 1;
memset(d,-1,sizeof(d));
queue<P> que;
que.push(P(g,h));
d[g][h] = 0;
while (!que.empty())
{
p = que.front();
que.pop();
for (int i = 0;i < 4;i ++)
{
int x = p.first + dx[i],y = p.second + dy[i];
if (check(x,y) && maze[x][y] != maze[p.first][p.second] && d[x][y] == -1)
{
que.push(P(x,y));
d[x][y] = 0;
ans ++;
}
}
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;i ++)
scanf("%s",maze[i] + 1);
for (int i = 0;i < m;i ++)
{
scanf("%d%d",&g,&h);
printf("%d\n",bfs());
}
return 0;
}
当看到询问的次数那么多,如果每一次询问再去BFS,那么结果可想而知。
如果有非常多的询问,眼看着一定会超时,那么就需要考虑把答案存起来,所以这个题就可以把答案存起来,然后当它询问时,就可以直接输出答案了。
再一个就是此题为连通图题(洪水填充题),故将每个连通图标识出来。
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1005;
const int MAX_M = 10000005;
int n,m,x,y;
struct maze
{
char c;
bool is;
}a[MAX_N][MAX_N];
int quex[MAX_M],quey[MAX_M];//通过数组实现的队列将遍历过的点存储起来。
int l = 1,r = 0;//l为队头,r为队尾。
int ans[MAX_N][MAX_N];
int dx[5] = {0,1,-1,0,0},dy[5] = {0,0,0,-1,1};//下标为0时,啥也不是,只是为了方便表达。
int main()
{
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= n;j ++)
scanf(" %c",&a[i][j].c);
for (int i = 1;i <= n;i ++)
{
for (int j = 1;j <= n;j ++)
{
if (a[i][j].is == 1)
continue;
l = 1,r = 0;
quex[++r] = i;
quey[r] = j;
a[i][j].is = 1;
int cnt = 1;//自身也算
while (l <= r)
{
for (int k = 1;k <= 4;k ++)
{
int nx = quex[l] + dx[k];
int ny = quey[l] + dy[k];
if (nx < 1 || nx > n || ny < 1 || ny > n) continue;
if (a[nx][ny].c == a[quex[l]][quey[l]].c) continue;
if (a[nx][ny].is == 1) continue;
a[nx][ny].is = 1;
quex[++r] = nx;
quey[r] = ny;
cnt ++;
}
l ++;
}
//ans[i][j] = cnt;//k=1时,存的就是i和j可能大佬不放心所以加上的。
for (int k = 1;k <= r;k ++)
{
ans[quex[k]][quey[k]] = cnt;//构成连通图。
}
}
}
while (m --)
{
scanf("%d%d",&x,&y);
printf("%d\n",ans[x][y]);
}
return 0;
}
看了orz的题解深有感触。
总结1:
迷宫新型实现方式:
struct maze
{
char c;
bool is;//相当于book数组,来标记是否被访问。
}a[MAX_N][MAX_N];
int quex[MAX_M],quey[MAX_M];//这里开的数组大小根据要存储的点数的最大值来决定。
int l = 1,r = 0;
这种方法可以存储所遍历的点,可以解决连通图等问题。
其中,当l > r时,队列为空,当l <= r时,队列不为空,入队操作:r ++,出队操作:l ++。
c语言实现的队列太鸡卵了,只能存数值。
struct queue
{
int data[];//改成qux[],quey[]又太麻烦了。
int head;//队首
int tail;//队尾
}
又看了orz的一篇题解,用的是暴力深搜。
大佬的思路:
迷宫中被划分出来很多个连通图,如果给每个连通图上色的话,为相同颜色,开动脑筋想一下,可以用不同数字来代替不同颜色。
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010;
const int MAX_M = 1000005;
char maze[MAX_N][MAX_N];
int iss[MAX_N][MAX_N];//不仅标记了遍历的点,还标记了连通图。
int ans[MAX_M];
int n,m,x,y,d = 1;
int total;
int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};
bool check(int x,int y)
{
return x <= n && x >= 1 && y <= n && y >= 1;
}
inline void dfs(int x,int y)
{
iss[x][y] = d;//这里的也可以写到遍历的循环体里面。
total ++;
for (register int i = 0;i < 4;i ++)
{
int nx = x + dx[i],ny = y + dy[i];
if (check(nx,ny) && iss[nx][ny] == 0 && maze[x][y] != maze[nx][ny])
{
dfs(nx,ny);
//iss[nx][ny] = d;
//total ++;
}
}
}
int main()
{
//std::ios::sync_with_stdio(false);
scanf("%d%d",&n,&m);
for (register int i = 1;i <= n;i ++)
for (register int j = 1;j <= n;j ++)
{
std::cin >> maze[i][j];
}
for (register int i = 1;i <= m;i ++)
{
std::cin >> x >> y;
if (iss[x][y] == 0)
{
total = 0;
//total = 1;
//iss[x][y] = d;
dfs(x,y);
ans[d++] = total;//记录每个连通图的点数,用d来记录第几个连通图。
}
std::cout << ans[iss[x][y]] << "\n";
}
return 0;
}
这位大佬的知识犹如深海,但人不是生来要给打败的,一个人能够被毁灭掉,但不能被打败。
总结2:
1.自加自减
对于后加加,加加操作都在表达式之后进行。
对于前加加,加加操作都在表达式之前进行,但是会考虑表达式内部的结合顺序,即考虑子表达式的问题,进行逐步加加的。
2.C语言register关键字—最快的关键字
register:这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率。注意是尽可能,不是绝对。
因为,如果定义了很多register变量,可能会超过CPU的寄存器个数,超过容量。所以只是可能。
3.std::ios::sync_with_stdio(false);
4.C++中std的使用和作用
5.inline内联函数的标记
最近更新时间:2021/05/15 -> 2021/05/22