首页 > 其他分享 >[ABC219E] Moat 题解

[ABC219E] Moat 题解

时间:2024-03-10 12:55:25浏览次数:20  
标签:格子 ABC219E vis int 题解 nx ny flag Moat

[ABC219E] Moat 题解

思路解析

一眼看到输入数据只有 \(4\) 行 \(4\) 列,直接想到状压枚举。可以直接枚举所有护城河所包含起来的格子,判断是否连通以及判断是否包含住了所有村庄。判断连通我选择用洪水填充,随便选一个包含着的格子,若可以通过当前格移动到所有被包含格就说明连通。以及还要判断被包围格子是否形成了一个环,例如:

其中蓝线表示护城河,绿色阴影表示护城河包围的格子。可见图中有两条护城河,不符合题意。为排除掉这种情况,我们判断每一个没有被选择的格子,判断它是否被护城河完全包围,也就是判断能否走到地图外即可。

时间复杂度:首先一次暴力枚举,然后对于每种情况需要判断是否为可行方案,洪水填充最多遍历 \(16\) 个格子,复杂度为 \(2^{16} \times 16\)。

code

#include<bits/stdc++.h>
using namespace std;
#define PII pair<int, int>
#define fir first
#define sec second
int v[8][8], flag[8][8], f[8][8], ans = 0;
bool vis[8][8];
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
void flood(int x, int y) {
	queue< PII > q;
	q.push({x, y});
	while(!q.empty()) {
		int xx = q.front().fir, yy = q.front().sec;
		q.pop();
		for(int i = 0; i < 4; i++) {
			int nx = xx + dx[i], ny = yy + dy[i];
			if(flag[nx][ny] && !f[nx][ny]) {
				f[nx][ny] = true;
				q.push({nx, ny});
			}
		}
	}
}
bool flood_loop(int x, int y) {
	queue< PII > q;
	q.push({x, y});
	memset(vis, false, sizeof(vis));
	vis[x][y] = true;
	while(!q.empty()) {
		int xx = q.front().fir, yy = q.front().sec;
		q.pop();
		for(int i = 0; i < 4; i++) {
			int nx = xx + dx[i], ny = yy + dy[i];
			if(!flag[nx][ny] && !vis[nx][ny]) {
				if(nx >= 1 && nx <= 4 && ny >= 1 && ny <= 4) {
					vis[nx][ny] = true;
					q.push({nx, ny});
				}
				else return true;
			}
		}
	}
	return false;
}
int check() {
	int x = 0, y = 0, cnt = 0;
	for(int i = 1; i <= 4; i++) {
		for(int j = 1; j <= 4; j++) {
			if(flag[i][j]) cnt++, x = i, y = j;
		}
	}
	memset(f, 0, sizeof(f));
	f[x][y] = 1;
	flood(x, y);	//洪水填充判断连通
	int sum = 0;
	for(int i = 1; i <= 4; i++) {
		for(int j = 1; j <= 4; j++) {
			if(f[i][j]) sum++;
		}
	}
	if(sum != cnt) return 0;	//不连通
	for(int i = 1; i <= 4; i++) {
		for(int j = 1; j <= 4; j++) {
			if(v[i][j] && !f[i][j]) return 0;	//若有村庄没被包含
		}
	}
	for(int i = 1; i <= 4; i++) {
		for(int j = 1; j <= 4; j++) {
			if(!flag[i][j] && !flood_loop(i, j)) return 0;	//被护城河完全包围
		}
	}
	return 1;
}
void dfs(int x, int y) {	//暴力枚举
	if(y > 4) y = 1, x++;
	if(x > 4) {
		ans += check();
		return;
	}
	flag[x][y] = 1;
	dfs(x, y + 1);
	flag[x][y] = 0;
	dfs(x, y + 1);
}
int main() {
	for(int i = 1; i <= 4; i++) {
		for(int j = 1; j <= 4; j++) {
			cin >> v[i][j];
		}
	}
	dfs(1, 1);
	cout << ans;
	return 0;
}

标签:格子,ABC219E,vis,int,题解,nx,ny,flag,Moat
From: https://www.cnblogs.com/2020luke/p/18064006

相关文章

  • ABC344G 题解
    ABC344G题解给定平面上\(n\)个点和\(q\)条直线,问对于每条线,有多少点在它上方。形式化的,对于直线\(y=ax+b\)统计有多少点\((x,y)\)满足\(y\geax+b\),即\(-ax+y\geb\)。故我们可以将所有点按照\(-ax+y\)排序,从而利用二分简单的得出结果。但是我们显然不可能暴力进......
  • 洛谷 P1099 题解
    洛谷P1099【NOIP2007提高组】树网的核题意简述给定一棵带边权无根树和一个正整数\(s\)。在这棵树的任意直径上截取一段长度不超过\(s\)的路径\(F\),使离\(F\)最远的点到\(F\)的距离最小,求出这个距离。思路记\(\delta(a,b)\)为\(a,b\)之间的路径。对于任意......
  • abc344_D - String Bags 题解
    一个月没有碰oi,感觉水平已经退化到负的了。来复健一下。D-StringBagslink题意:给你\(n\)组字符串组,按\(1\)~\(n\)的顺序,对于每组字符串组,可从中至多选一个字符串。求能否用所选串按顺序拼接成指定串,以及选取字符串的最小个数。然后读完题发现是个\(01\)背包;对于第......
  • AT_abc344_e 题解
    本文同步发表于洛谷。赌狗天天输的一集。赛时各种【数据删除】原因导致没做出来。大意给你一个长度为\(N\)的序列\(A=(A_1,\ldots,A_N)\)。保证\(A\)中的元素是不同的。你要处理\(Q\)个操作。每个操作是以下两种类型之一:1xy:在\(A\)中元素\(x\)后面紧接着插入......
  • AT_abc344_d 题解
    赌狗天天输的一集。大意你最开始有一个空字符串\(S\)。你还有编号为\(1,2,\dots,N\)的袋子,每个袋子都包含一些字符串。袋子\(i\)包含\(A_i\)个字符串\(S_{i,1},S_{i,2},\dots,S_{i,A_i}\)。对\(i=1,2,\dots,N\)重复以下步骤仅一次(这里原题没有讲清楚):......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    分析考虑时光倒流。对于需要合并的两个连通块\(x,y\),其合并之后的最远点对距离一定是合并之前的两组点对中产生的。在合并的时候枚举点对,取距离最大值即可。由于我们是倒着来的,所有连通块的最远点对距离最大值不减,所以能直接在合并之后取最大值。维护连通块用并查集即可。复杂......
  • P10237 [yLCPC2024] E. Latent Kindom 题解
    分析一眼了非最优解。考虑二分答案。对于二分出来的中位数\(x\),到\(a_i\)和\(a_j\)里边又去二分。得到两个序列中不超过\(x\)的数的数量。若这个数量\(cnt\ge\lceil\frac{len_{i}+len_{j}}{2}\rceil\),则\(x\)可能成为中位数,然后继续二分即可。把序列离散化,复杂度......
  • [ABC219F] Cleaning Robot 题解
    [ABC219F]CleaningRobot题解思路解析要点:将整个图拆分成每一轮的每一个点单独考虑贡献。首先看到\(k\le10^{12}\)发现不能直接枚举\(k\)轮,于是开始找每一轮的规律。首先可以知道,如果操作固定,那么起点和路径上每一个点以及终点的相对位置不会改变。也就是说每一轮的起......
  • CF1583E Moment of Bloom 题解
    题意:给定一张\(n\)个点\(m\)条边无向连通图,以及\(q\)个点对\((a,b)\),出事每条边权值为\(0\)。对于每个点对我们需要找一条从一个点到另一个点的简单路径,将所有边的权值加一。要求构造一种方案使得每条边权值都是偶数。如果不行,输出最少还要几个点对才能满足要求。\(n,m......
  • CF1634E Fair Share 题解
    题意:给定\(m\)个长度为偶数的数组,\(L,R\)是初始为空的两个多重集。将每个数组恰好一半的数放入\(L\),另一半放入\(R\),要求最后\(L=R\),要求构造方案或判断无解。\(m\le10^5,\sumn\le10^5\)。思路:首先我们不难想到,对于同一个数组内相同的值,可以成双除去,所以我们可以......