BFS 广度优先树与腾讯马拉松第五场第三题:小明水滴问题

写作缘由:腾讯马拉松第五场第三题----小明水滴游戏。参考http://blog.csdn.net/dyx404514/article/details/8720661,运用了BFS的思想,故重新阅读算法导论中广度优先树

写作目的:熟悉广度优先树,记忆其中的关键概念,能熟练写出其伪代码,并争取下次遇到含有BFS思想的题目时,能够更快想到BFS

参考资料《算法导论》

概念回顾

  1. 在给定图G(V,E)和一个
  2. 特定的源顶点s下,搜索所有的顶点,并计算s到达这所有顶点的剧烈,还能生成一个广度优先树
  3. 算法会首先发现和s距离为k的顶点,然后再搜索距离为k+1的顶点。
  4. BFS( G,s)
    for each vertex u ∈V[G] -{s}
      do color[u]  ← WHITE
        d[u] ← ∞
        ∏[u] ← NIL
    color[s] ← GRAY
    d[s] ← 0
    ∏s]  ← NIL
    Q ← 空集
    ENQUEUE(Q,s)
    while Q != 空集
      do u ← DEQUEUE(Q)
         for each v ∈ Adj[u]
            do if color[v] = WHITE
                 then color[v] ← GRAY
                      d[v] ← d[u] +1
                      ∏[v] ← u
                      ENQUEUE(Q,v)
      color[u] ← BLACK
    颜色变量存储于color中,包括三种颜色:黑色(完全探索到包括其相邻的节点)灰色(探索到,但是其相邻节点没有被全部探索到)白色(未探索到);一个点的父节点存储于∏[u]中;一个顶点被置为灰色时插入队列,而当顶点从队列出队列后,它将被置为黑色
  5. 过程BFS运行时间为O(V+E)。
  6. 当运行终止时,对于所有v,d[v]都是其到顶点的最短距离。

腾讯马拉松第五场第三题---小明水滴游戏

代码与题目

//Input
//题目包含多组测试用例;
//对于每组数据,首先是6行,每行有6个整数数字,每个数字的范围为0~4;当数字为0时,表示空格子,当数字为1~4时,表示1~4级的水滴;
//然后第七行是一个整数m,表示有m个操作;接下来是m行,每行有两个整数x, y ,表示在(x,y)放入一滴水。
//特别说明:每次都是在全部的水滴静止后才进行下一次操作,也就是说只有在方格内没有任何飞溅的小水滴时才能放入一滴水。
//
//[Technical Specification]
//1 <= m <= 10
//1 <= x, y <= 6
// 
//
//Output
//对于每组测试数据,请输出m个操作之后6*6方格内水滴的样子,每组数据的输出后面跟着一个空行。
// 
//
//Sample Input
//0 0 0 4 0 4
//0 0 0 0 0 0
//1 0 0 4 0 4
//0 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 1 0 0
//1
//1 6
//0 0 0 4 0 4
//0 2 0 4 0 4
//0 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 0 0 0
//1
//1 6
//2 2 0 2 0 3
//3 3 0 1 3 1
//2 2 2 4 0 4
//2 4 4 2 2 3
//3 3 2 4 0 1
//1 3 4 3 0 1
//6
//5 3
//5 3
//3 3
//3 2
//2 1
//6 3
// 
//
//Sample Output
//0 0 0 0 0 0
//0 0 0 0 0 0
//2 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 2 0 0
//
//0 0 0 0 0 0
//0 3 0 0 0 0
//0 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 0 0 0
//0 0 0 0 0 0
//
//0 4 0 2 0 3
//0 0 0 4 3 2
//0 0 0 0 0 0
//0 0 0 0 4 4
//0 0 0 0 0 4
//4 0 0 0 0 3
//
//Hint
//
//第一组数据:
//(1,6)爆裂,然后在第二秒(1,4)(2,6)爆裂,在第四秒,两滴水同时到达(3,4), (3,4)变成了6,爆裂,然后在第七秒(3,1)(6,4)变成了2。

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <queue>

using namespace std;
class FlyWater
{
public:
	int x;
	int y;
	int t;//影响时刻
	int direc;
};
int place[7][7];
int time[7][7];//爆裂时间
bool CheckInPlace(int x,int y)
{
	if(x<=6 && x>=1 && y<=6 && y>=1)
		return true;
	else 
		return false;
}
int direction[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};//上下左右
//形参为坐标
void BFS(int x,int y)
{
	queue<FlyWater> q;
	++place[x][y];
	if(place[x][y] > 4)
	{
		FlyWater fly;
		fly.x = x;fly.y = y;fly.t = 0;fly.direc = -1;
		time[x][y] = 0;//7:47
		q.push(fly);
	}
	while(!q.empty())
	{
		FlyWater water = q.front();//pop不返回
		q.pop();
		int xx = water.x;int yy = water.y;int tt = water.t;int dd = water.direc;
		if (dd == -1)
			place[xx][yy] = 0;
		for(int i =0;i < 4;i++)//上下左右
		{
			if(dd != -1 && dd != i)
				continue;
			int a = xx + direction[i][0];int b = yy + direction[i][1];
			if(CheckInPlace(a,b))
			{
				if(place[a][b] == 0)
				{
					water.x = a;water.y = b;water.t = tt + 1;water.direc = i;
					q.push(water);
				}
				else if (place[a][b] < 4 )
				{
					++place[a][b];
				}
				else if(place[a][b] == 4)
				{
					++place[a][b];//模拟
					time[a][b] = tt + 1;//8:02  1.原先错误设置为time[a][b]++;9:02 2.原先是++t
					water.x = a;water.y = b;water.t = tt + 1;water.direc = -1;
					q.push(water);
				}
				else
				{
					//顺着上面  注意:不是顺着上面 根据先前值
					if((tt + 1) <= time[a][b])
					{
						++place[a][b];//不起作用,都会成为0
					}
					else
					{
						//此时原先的水珠已经爆破,只是还没有让place[a][b] = 0,所以现在的水珠还将继续飞行,因为一旦为0,终身为0
						water.x = a;water.y = b;water.t = tt + 1;water.direc = i;
						q.push(water);
					}
				}
			}
		}
	}
}
int main()
{
	while(cin >> place[1][1])
	{
		//ifstream infile("C:\\Users\\Administrator\\Desktop\\Algorithm\\Problem3\\data3.txt");
		for(int i = 1;i<=6;i++)
		{
			for(int j = 1;j<=6;j++)
			{
				if(i==1 && j==1)
					continue;
				cin >> place[i][j];
			}
		}
		int cases;
		cin >> cases;
		while(cases--)
		{
			memset(time,-1,sizeof(time));/很重要的初始化
			int x;
			int y;
			cin >> x >>y;
			BFS(x,y);		
		}
		for(int i = 1;i<=6;i++)
		{
			for(int j = 1;j<=6;j++)
			{
				if(j != 6)
					cout << place[i][j]<<" ";
				else
					cout<<place[i][j];

			}
			cout<<endl;
		}
		cout << endl;
	}
	system("pause");
	return 0;
}

过程与心情:

此题前后断断续续用了三天,第一晚上自己睡前想了下,思路在于:...算了,不提也罢,无算法而言,纯属模拟整个游戏,第二天看大牛说BFS算法,遂将算法导论的BFS复习了下,最后动手开写,到不停得遇到BUG,终于搞定,前面的挫败感也一扫而光了,弄得昨晚舜天的比赛也没看,还好,看了估计火气也大,三连败了啊都。

算法:

主要是BFS算法,用自己的话描述:其实是将每一滴即将运动的水滴压入队列,BFS:发现和s距离为k的顶点,然后再搜索距离为k+1的顶点  ,这题是先按时间先影响到的水滴压入队列,出队列的时候再处理,典型的FIFO,运行的时间复杂度是线性的。

编程期间遇到的BUG与易错点

  1. 定义一个爆破时间的数组time[7][7],否则不好判断此时经过时,水珠是要被挡住,还是穿过,因为此时可能还没有处理到爆破水滴,根据time[i][j]与即将运行到此处的时间tt+1进行比较
  2. 爆破时间的初始化  memset(time,-1,sizeof(time))
  3. 谨慎使用++t,尤其是循环中内部使用到++t ,最后发现的bug就是这个,寻找了很久
  4. 爆破时间的准确设置很重要


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值