BFS 简单应用

前言:

BFS 即广度优先搜索(或宽度优先搜索),具体定义和实现不在赘述。

本文所有代码前的开头头文件,宏定义和命名空间如下(只是一些常用的 define 和一个快读):

#include <bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define ll long long
#define CI const int
#define RI int
#define W while
#define gc getchar
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define Mt(a,x) memset((a),(x),sizeof(a))
using namespace std;
namespace SlowIO {
	void Readc (char& c) {W (isspace (c = gc ()));}
	Tp void Read (Ty& x) {char c; int f = 1; x = 0; W (! isdigit (c = gc ())) f = c ^ '-' ? 1 : -1; W (x = (x * 10) + (c ^ 48), isdigit (c = gc ())); x *= f;}
	Ts void Read (Ty& x, Ar&... y) {Read (x); Read (y...);}
} using namespace SlowIO;

1.[USACO23OPEN] Field Day S

summarization

给定 \(n\) 个长度为 \(m\) 的字符串(仅由 GH 组成),定义 calc(x,y) 表示两个字符串不一样的位的个数,需要求出每一个字符串 \(s\)\(\max\limits_{i\in\text{给出的字符串}}calc(s,i)\) 。(\(1\le m\le18,1\le n\le10^5\)

solution

明显的,考虑转化为求 \(\min\)。先将字符串转化为 01 序列,即可以表示为一个十进制整数。

定义 “一个整数 \(x\)\(\min/\max\)”:即为此整数 \(x\) 对应的字符串 \(s_x\)\(\min/\max_{i\in\text{给出的字符串}}calc(s_x,i)\)

对于一个整数 \(x\),考虑求 \(y=2^m-1-x\)\(\min\),即为 \(x\)\(\max\)

证明:易知,\(y\) 即为 \(x\) 的前 \(m\) 位取反后的数值。求出和 \(y\) 最接近的值,就是和前 \(m\) 位取反后的 \(x\) 的最远的值。得证。

定义 “一步”:将一个整数的二进制表示上的一位取反。

所以问题变为:求 \(y\) 最少经过几步可以变为给定的整数(字符串可以转化为整数),求得后将 \(m\) 减去它即为答案。

考虑一个问题:在一个迷宫中有一个入口和若干个出口,需要求出从入口开始走出迷宫的最小步数。

基本思路是反向求解,将出口加入 BFS 队列中,通过 BFS 求得最短的出口走向入口的路径。

类比到此题,将给定整数加入队列,通过 BFS 一步一步求得给定整数到 \(0\sim2^m-1\) 所有状态的最少步数,即为所有状态下最短到达某个目标状态的步数。

最终对于 \(\forall x\),求出 \(2^m-1-x\)\(\min\),输出 \(m-\min\) 即可。

得解。

code

CI N = 1e5, B = (1 << 18); int m, n, a[N + 5], dis[B + 5]; struct node {int x; int val;} h, p, r; queue <node> q;
int main () {
	RI i, j; for (Read (m, n), i = 1; i <= n; ++ i) {char ch = getchar (); W (ch != '\n') a[i] = (a[i] << 1) + (ch == 'H'), ch = getchar ();} Mt (dis, -1);
	for (i = 1; i <= n; ++ i) {h.x = a[i]; h.val = 0; q.push (h); dis[a[i]] = 0;} W (! q.empty ()) {
		p = q.front (); q.pop (); for (i = 0; i < m; ++ i) {int o = p.x ^ (1 << i); if (dis[o] == -1) dis[o] = p.val + 1, r.x = o, r.val = p.val + 1, q.push (r);}
	} for (i = 1; i <= n; ++ i) {printf ("%d\n", m - dis[(1 << m) - 1 - a[i]]);}
    return 0;
}
posted @ 2023-04-27 23:26  ClapEcho233  阅读(23)  评论(0编辑  收藏  举报