题解
A - Oil Deposits
题目:含有油的地块称为口袋。如果两个口袋相邻,则它们是相同油藏的一部分。油沉积物可能非常大并且可能包含许多口袋。确定网格中包含多少不同的油藏。
- BFS求连通块
- c语言形式的输入输出有时候会很方便
int main()
{
while(~scanf("%d%d",&n,&m))
{
cnt=0;
if(n==0)///输入0 0 退出
break;
for(int i=0;i<n;i++)
{
scanf("%s",Map[i]);
}
······
printf("%d\n",cnt);
}
return 0;
}
- C++形式的模板全部代码
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
const int maxn=105;
char Map[maxn][maxn];
int n,m,cnt=0;
int dir[8][2]={{1,0},{1,1},{1,-1},{-1,0},{-1,1},{-1,-1},{0,1},{0,-1}};
struct node
{
int x;
int y;
}now,next;
void BFS(int x,int y)
{
now.x=x;
now.y=y;
Map[x][y]='*';
queue<node> q;
q.push(now);
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=0;i<8;i++)
{
int xx=now.x+dir[i][0];
int yy=now.y+dir[i][1];
if(xx>=0&&xx<n&&yy>=0&&y<m&&Map[xx][yy]=='@')
{
Map[xx][yy]='*';
next.x=xx;
next.y=yy;
q.push(next);
}
}
}
}
int main()
{
while(cin>>n>>m&&n&&m)
{
cnt=0;
if(n==0)
break;
for(int i=0;i<n;i++)
{
scanf("%s",Map[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(Map[i][j]=='@')
{
cnt++;
BFS(i,j);
}
}
}
cout << cnt << endl;
}
return 0;
}
B - Lake Counting
题目:由于最近的降雨,水汇集在Farmer John’s田地的不同地方,其由N×M(1 <= N <= 100; 1 <= M <= 100)的正方形矩形表示。每个方块包含水(‘W’)或旱地(’。’)。农夫约翰想弄清楚他的田地里有多少个池塘。池塘是一组连接的正方形,其中有水,其中一个正方形被认为与其所有八个邻居相邻。 给出农夫约翰的田地图,确定他有多少池塘。
同样是连通块,与上一题差别很小,把判断条件改一下就好
C - Red and Black
题目:这间长方形客房铺有方形瓷砖。每个瓷砖都是红色或黑色。一个男人站在黑色的瓷砖上。从瓷砖中,他可以移动到四个相邻瓷砖中的一个。但他不能在红瓦上移动,他只能在黑色瓷砖上移动。 通过重复上述动作来计算他可以达到的黑色瓷砖的数量。
本来也是个套模板的连通块问题,就是最后一组数据总会会受到倒数第二组数据影响。回来听说是字符组的初始化问题(为什么没有被边界限制解决掉,还是不太明白。。。)。
- BFS版本
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int maxn=105;
char Map[maxn][maxn];
int n,m,cnt=0;
int xs, ys;
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
int x, y;
} now,next;
void BFS(int x,int y)
{
now.x=x;
now.y=y;
Map[x][y]='#';
queue<node> q;
q.push(now);
while(!q.empty())
{
now=q.front();
q.pop();//读取and删除第一个元素
for(int i=0; i<4; i++)
{
int xx=now.x+dir[i][0];
int yy=now.y+dir[i][1];
if(xx>=0&&xx<n&&yy>=0&&y<m&&Map[xx][yy]=='.')
{
Map[xx][yy]='#';
next.x=xx;
next.y=yy;
q.push(next);
cnt++;
}
}
}
}
int main()
{
while(cin>>m>>n&&n&&m)
{
memset(Map, '#', sizeof Map);//初始化在这里!!!
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
{
cin >> Map[i][j];
if(Map[i][j] == '@')
{
xs = i; ys = j;//记录起始点
}
}
cnt=1;
BFS(xs,ys);
cout<<cnt<<endl;
}
return 0;
}
- DFS版本
#include<iostream>
using namespace std;
int m,n,cnt;
char map[105][105];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
void dfs(int x,int y)//bfs的最后一个样例让我自闭
{
cnt++;
map[x][y]='#';
for(int i=0;i<4;i++)
{
int nx=x+dir[i][0];
int ny=y+dir[i][1];
if(nx>=0 && nx<n && ny>=0 && ny<m && map[nx][ny]=='.')
dfs(nx,ny);
}
}
int main()
{
while(cin>>m>>n && m!=0 && n!=0)
{
cnt=0;
for(int i=0;i<n;i++)
cin>>map[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(map[i][j] == '@')
{
dfs(i,j);
break;
}
}
}
cout<<cnt<<endl;
}
}
E - Catch That Cow
题目:在同一个数轴上,人在 ( N , 0 ) (N,0) (N,0),牛在 ( K , 0 ) (K,0) (K,0),每一次人可以选择从 ( X , 0 ) (X,0) (X,0)到 ( X + 1 , 0 ) (X+1,0) (X+1,0)或 ( X − 1 , 0 ) (X-1,0) (X−1,0)或 ( 2 X , 0 ) (2X,0) (2X,0),求人需要多久到达牛的位置。
- BFS求最短路。
- BFS函数里面会有x+1,x-1,x*2三种情况的讨论。
- BFS部分和越界判断部分
int booll(int x)//检查是否越界
{
if(x<0 || x>=N || Map[x])
return 0;
return 1;
}
int bfs(int x)
{
queue<node> q;
now.x = x;
now.time = 0;
Map[x] = 1;
q.push(now);
while(!q.empty())
{
now = q.front();
q.pop();
if(now.x == k)//到了就出去了
return now.time;
next = now;
next.x = now.x+1;//三种情况可以设计在一个for循环里面
if(booll(next.x))
{
next.time = now.time+1;
Map[next.x] = 1;
q.push(next);
}
next.x = now.x-1;
if(booll(next.x))
{
next.time = now.time+1;
Map[next.x] = 1;
q.push(next);
}
next.x = now.x*2;
if(booll(next.x))
{
next.time = now.time+1;
Map[next.x] = 1;
q.push(next);
}
}
return -1;
}
G - Nightmare
题目:迷宫有一个出口,Ignatius应该在炸弹爆炸之前离开迷宫。炸弹的最初爆炸时间设定为6分钟。为了防止炸弹爆炸,Ignatius必须缓慢移动,只可以上下左右四个方向,一步需要1分钟。迷宫中的某些区域包含一个Bomb-Reset-Equipment。他们可以将爆炸时间重置为6分钟。
鉴于迷宫和Ignatius的起始位置的布局,判断Ignatius是否可以离开迷宫,如果可以的话,输出他必须用来找到迷宫出口的最短时间,否则输出-1。
以下是一些规则:
1。我们可以假设迷宫是一个2阵列。
每一分钟,伊格纳修斯只能到达最近的一个区域,他不应该走出边境,当然他也不能走在墙上。
3.如果伊格纳修斯在爆炸时间变为0时到达出口,他就无法走出迷宫。
4.当爆炸时间变为0时,如果伊格纳修斯到达包含炸弹 - 休息设备的区域,他就无法使用该设备重置炸弹。
5.炸弹重置设备可以根据需要多次使用,如果需要,Ignatius可以根据需要多次到达迷宫中的任何区域。
6.重置爆炸时间的时间可以忽略,换句话说,如果Ignatius到达包含Bomb-Rest-Equipment的区域,并且爆炸时间大于0,则爆炸时间将重置为6。
- BFS求最短路
- 带有特别条件的BFS最短路,还有一些剪枝的东西吧。
#include<iostream>
#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;
const int N = 8;
const int M = 8;
char mp[N+2][M+2];
int vistime[N+2][M+2];//上次到达某点剩余的的时间
int n,m;
struct Node
{
int x,y;
int t,step;
}now,nextt;
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
int bfs(int sx,int sy)
{
queue<Node>q;
now.x = sx; now.y = sy;
now.t = 6; now.step = 0;
vistime[now.x][now.y] = 6;
q.push(now);
while (!q.empty())
{
now = q.front();
q.pop();
for (int i = 0;i < 4;++i)
{
int xx = now.x + dir[i][0];
int yy = now.y + dir[i][1];
if (xx>=0&&yy>=0&&xx<n&&yy<m)
{
nextt.x=xx;
nextt.y=yy;
nextt.step=now.step+1;
nextt.t = now.t - 1;
if (mp[nextt.x][nextt.y] == 4)
{
if (6 > vistime[nextt.x][nextt.y])//避免超时
{
nextt.t = 6;
q.push(nextt);
vistime[nextt.x][nextt.y] = 6;
}
else
continue;
}
else if (mp[nextt.x][nextt.y] == 1)
{
if (nextt.t == 1) continue;//下一步走到哪都是死
if (vistime[nextt.x][nextt.y] < nextt.t)//剪枝,上一种方法走到这里时间更少
{
q.push(nextt);
vistime[nextt.x][nextt.y] = nextt.t;//重置剩下的时间
}
}
else if (mp[nextt.x][nextt.y] == 3)//走到终点了
{
return nextt.step;
}
}
}
}
return -1;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
int sx,sy;
scanf("%d%d",&n,&m);
for (int i = 0;i < n;++i)
{
for (int j = 0;j < m;++j)
{
scanf("%d",&mp[i][j]);
if (mp[i][j] == 2)
{
sx = i,sy = j;
}
}
}
memset(vistime,0,sizeof vistime);
printf("%d\n",bfs(sx,sy));
}
return 0;
}
H - Knight Moves
题目:计算国际象棋中的骑士从另一个点到达一个点所需的最小移动次数。骑士可以移动的位置:
- BFS求最短路
- 简简单单套模板就好。变一下方向数组,记录一下起始位置,只调用起始位置的BFS函数就行。
- 方向数组
int dir[8][2]= {{1,2},{2,1},{1,-2},{2,-1},{-1,2},{-2,1},{-1,-2},{-2,-1}};
- BFS函数调用
cin >> xs >> ys >> xe >> ye ;
if(xs == xe && ys == ye)
cout << 0 << endl;
else
{memset(Map, 0, sizeof Map);
ans=BFS(xs,ys);
cout << ans <<endl;
}