USACO The Castle 位运算 FloodFill

参考思路:http://blog.csdn.net/dragonfly_xp/article/details/5504031

http://blog.tianya.cn/blogger/post_show.asp?BlogID=1144082&PostID=10566902

学习了FloodFill方法以及位运算 if((wall[row][col] & 1) == 0) FloodFill(row, col - 1, color);
注意题目里说了:choose 'N' before 'E'。 所以最后在遍历墙,合并房间的时候,注意顺序,从最西南角,先向N遍历每一列,然后向E遍历。即外层循环遍历column,内层循环遍历row。

算法分析: 
  这是一道比较综合的题目,我觉得关键就是在于如何处理好给的数据。 
  开始一看,觉得用这样的方式描述一个矩阵还不大习惯。可仔细一看,发现四个方向分别用 
  1、2、4、8表示,这就让我想起了二进制。再把样例加以分析,拿11来说,把它化成二进制为1011,从第一位到第四位分别对应北东南西,然后在存储下来,这样就把给的信息转化成能直接运用的了! 
  再来看,它的几个任务。 
  1、求房间数 
  一开始就觉得跟迷宫类似。便选择了用BFS。 
  从(1,1)开始对每个未染色的房间染色。每次到此块全部染色完,就累加ROOM。 
  进行多次BFS,直到全部房间都染色,便得出第一问结果。 
  2、求最大房间大小 
  因为已经给不同房间染了不同色,这样就能很方便的找出最大房间大小。 
  3、移除一面墙能得到的最大的房间的大小 
  这里,我选择了用枚举每个墙来找最优解。 
  因为在之前先记录下了每个房间的大小,所以只需要判断移除的墙两侧不为同一房间,且比最优值更优,就可以更新。 


我的代码

/*
ID: wangxin12
PROG: castle
LANG: C++
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;

#define MAX 51

int wall[MAX][MAX];
int M,N;  // M cols, N rows
int i, j; //计数用

int visited[MAX][MAX];
int roomnum;
vector<int> roomsize;
int bigroom;

void FloodFill(int row, int col, int color);

int vergeSize;
int vergeRow;
int vergeCol;
char vergeDirection;

int main() {
	//input
	ifstream fin("castle.in");
	ofstream fout("castle.out");
	fin>>M>>N;
	for(i = 0; i < N; i++) {
		for(j = 0; j < M; j++) {
			int temp;
			fin>>temp;
			wall[i][j] = temp;
		}
	}
	fin.close();

	//floodfill 求房间数目
	for(i = 0; i < N; i++) {
		for(j = 0; j < M; j++) {
			if(visited[i][j] == 0) FloodFill(i, j, ++roomnum);
		}
	}

	fout<<roomnum<<endl;

	//求最大的房间大小
	for(i = 0; i < roomnum; i++) roomsize.push_back(0);
	for(i = 0; i < N; i++) {
		for(j = 0; j < M; j++) {
			int temp = visited[i][j];
			roomsize[temp - 1]++;
		}
	}
	for(i = 0; i < roomnum; i++) {
		if(bigroom < roomsize[i]) bigroom = roomsize[i];
	}
	fout<<bigroom<<endl;

	//求合并后最大的房间
	for(j = 0; j < M; j++) {
		for(i = N - 1; i >= 0; i--) {
			//和North的墙
			if( i - 1 >= 0 && visited[i][j] != visited[i - 1][j]) {
				int first = visited[i][j];
				int second = visited[i - 1][j];
				int total = roomsize[first - 1] + roomsize[second - 1];
				if(vergeSize < total) {
					vergeSize = total;
					vergeRow = i + 1;
					vergeCol = j + 1;
					vergeDirection = 'N';
				}
			}
			//和East的墙
			if( j + 1 < M && visited[i][j] != visited[i][j + 1]) {
				int first = visited[i][j];
				int second = visited[i][j + 1];
				int total = roomsize[first - 1] + roomsize[second - 1];
				if(vergeSize < total) {
					vergeSize = total;
					vergeRow = i + 1;
					vergeCol = j + 1;
					vergeDirection = 'E';
				}
			}
		}
	}
	fout<<vergeSize<<endl;
	fout<<vergeRow<<" "<<vergeCol<<" "<<vergeDirection<<endl;


	//Output
	//ofstream fout("out.txt");

	fout.close();
    
	return 0;
}

void FloodFill(int row, int col, int color) {
	if(row < 0 || col < 0 || row >= 50 || col >= 50) return;

	if(visited[row][col] != 0) return;

	visited[row][col] = color;

	if((wall[row][col] & 1) == 0) FloodFill(row, col - 1, color);
	if((wall[row][col] & 2) == 0) FloodFill(row - 1, col, color);
	if((wall[row][col] & 4) == 0) FloodFill(row, col + 1, color);
	if((wall[row][col] & 8) == 0) FloodFill(row + 1, col, color);

	return;
}




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值