usaco 2.1

进入第二章:上来就是一个比较繁琐的图论,求迷宫的最大联通块,然后允许拆一块墙,在求一次此时的最大联通块

求联通块:dfs+枚举每一块墙, 要注意的是题目说要尽量靠西的答案,和尽量靠南的答案,那么在枚举墙的时候应

for (int j = 1; j < M; j++)

         for (int i = N; i > 0; i--)

通过自底向上,从左到右枚举就省去了比较

2: 每面墙会在两个小块内被表示:那么枚举时按题目要求,每个小块只用看他的N,E墙即可。

3:由于2,要将一面墙“打破”, 将两个相邻块的bool数组置为false

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

#include <iostream>
#include <fstream>
#include <cstring>
#include <algorithm>
using namespace std;

ifstream fin("castle.in");
ofstream fout("castle.out");

int M, N;
int maxspace, number, tmp, maxs;
const int MAXN = 55;
bool vis[MAXN][MAXN];
bool sta[MAXN][MAXN][4];
int posx, posy;
char direc;

void check(int i, int j, int n)
{
	if (n % 2 == 1) {
		sta[i][j][2] = true; 
		n -= 1;
	}
	if (n >= 8) {
		sta[i][j][1] = true;
		n -= 8;
	}
	if (n >= 4) {
		sta[i][j][3] = true;
		n -= 4;
	}
	if (n == 2) {
		sta[i][j][0] = true;
	}
}

void dfs(int i, int j)
{
	vis[i][j] = true;
	tmp ++;
	if (!sta[i][j][0] && !vis[i-1][j])  dfs(i-1, j);
	if (!sta[i][j][1] && !vis[i+1][j])  dfs(i+1, j);
	if (!sta[i][j][2] && !vis[i][j-1])  dfs(i, j-1);
	if (!sta[i][j][3] && !vis[i][j+1])  dfs(i, j+1);
}

void solve()
{
	tmp = 0;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			if (!vis[i][j]) {
				number ++;
				dfs(i, j);
				if (tmp > maxspace) maxspace = tmp;
				tmp = 0;
			}
		}
	}
}

void reset()
{
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			vis[i][j] = false;
		}
	}
	for (int j = 0; j <= M + 1; j++) {
		vis[0][j] = true;
		vis[N+1][j] = true;
	}
	for (int i = 0; i <= N + 1; i++) {
		vis[i][0] = true;
		vis[i][M+1] = true;
	}
}


int main()
{
	fin >> M >> N;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			fin >> tmp;
			check(i, j, tmp);
		}
	}
	solve();
	fout << number << endl;
	fout << maxspace << endl;
	for (int j = 1; j <= M; j++) {
		for (int i = N; i >= 1; i--) {
			if (sta[i][j][0]) {
				sta[i][j][0] = sta[i-1][j][1] = false;
				reset();
				solve();
				if (maxs < maxspace) {
					maxs = maxspace;
					posx = i; posy = j; direc = 'N';
				}
				sta[i][j][0] = sta[i-1][j][1] = true;
			}	
			if (sta[i][j][3]) {
				sta[i][j][3] = sta[i][j+1][2] = false;
				reset();
				solve();
				if (maxs < maxspace) {
					maxs = maxspace;
					posx = i; posy = j; direc = 'E';
				}
				sta[i][j][3] = sta[i][j+1][2] = true;
			}
		}
	}
	fout << maxs << endl;
	fout << posx << " " << posy << " " << direc << endl;
}	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值