// // // // // // // // // // // // // //

关于 BFS

bfs与优化

前言:

这玩意比深搜好多了好吗

深搜是真的恶心人


1. 电路维修(打开灯泡)

思路:

根据题意建立边权为 0 或 1 的无向图

双端队列 bfs

code:

/*
  Time: 12.27
  Worker: Blank_space
  Source: #2632. 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On
*/
/*--------------------------------------------*/
#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, m, dis[C];
struct edge{
	int v ,w, nxt;
}e[C];
int head[C], js;
bool vis[C];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v, int w)
{
	e[++js].v = v; 
	e[js].w = w;
	e[js].nxt = head[u];
	head[u] = js;
}
/*----------------------------------------函数*/
int main()
{
    n = read(); m = read();
    for(int i = 1; i <= n; i++)
    	for(int j = 1; j <= m; j++)
    	{
    		char s; bool p = 0;	cin >> s;
    		if(s == '/') p = 1;
    		add_edge((i - 1) * (m + 1) + j, i * (m + 1) + j + 1, p);
    		add_edge(i * (m + 1) + j + 1, (i - 1) * (m + 1) + j, p);
    		add_edge((i - 1) * (m + 1) + j + 1, i * (m + 1) + j, p ^ 1);
    		add_edge(i * (m + 1) + j, (i - 1) * (m + 1) + j + 1, p ^ 1);
    	}
    for(int i = 1; i <= n * m + n + m + 1; i++) dis[i] = INF;
	deque <int> q;
    q.push_back(1); dis[1] = 0;// vis[1] = 1;
    while(!q.empty())
    {
    	int u = q.front();
    	q.pop_front();
    	if(vis[u]) continue;
    	vis[u] = 1;
    	for(int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v, w = e[i].w;
    		dis[v] = min(dis[v], dis[u] + w);
    		if(w) q.push_back(v);
    		else q.push_front(v);
    	}
    }
    if(dis[(m + 1) * (n + 1)] == INF) puts("NO SOLUTION");
    else printf("%d", dis[(m + 1) * (n + 1)]);
	return 0;
}

2. 魔板

思路:

看到书上是康托展开

但是这个题是按照自己的思路写的

有一点dp的思想

先把当前的状态写成八个整数的形式

由每一种方式作为一种状态

map映射

通过三种操作搜索能够转移的状态

每一种状态第一次被搜到的时候就是达到这一状态的最小次数 通过这一点记录路径

code:

/*
  Time: 12.27
  Worker: Blank_space
  Source: #10027. 「一本通 1.4 例 2」魔板
  以每种情况作为一种状态 map映射
*/
/*--------------------------------------------*/
#include<cstdio>
#include<iostream>
#include<map>
#include<queue>
#include<string>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int E = 12345678;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int a[10];
map <int, int> dis;
map <int, string> path;
queue <int> q;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
int g()
{
	int sum = 0;
	for(int i = 1; i <= 8; i++) sum = sum * 10 + a[i];
	return sum;
}
void change(int opt)
{
	if(opt == 1)
		for(int i = 1; i <= 4; i++) swap(a[i], a[9 - i]);
	if(opt == 2)
	{
		int x = a[4], y = a[5];
		for(int i = 3; i >= 1; i--) a[i + 1] = a[i];
		for(int i = 5; i <= 7; i++) a[i] = a[i + 1];
		a[1] = x; a[8] = y;
	}
	if(opt == 3)
	{
		int x = a[7];
		a[7] = a[6];
		a[6] = a[3];
		a[3] = a[2];
		a[2] = x;
	}
	if(opt == 4)
	{
		int x = a[1], y = a[8];
		for(int i = 1; i <= 3; i++) a[i] = a[i + 1];
		for(int i = 7; i >= 5; i--) a[i + 1] = a[i];
		a[4] = x; a[5] = y;
	}
	if(opt == 5)
	{
		int x = a[7];
		a[7] = a[2];
		a[2] = a[3];
		a[3] = a[6];
		a[6] = x;
	}
}
void cover(int x)
{
	for(int i = 8; i >= 1; i--)
	{
		a[i] = x % 10;
		x /= 10;
	}
}
/*----------------------------------------函数*/
int main()
{
    for(int i = 1; i <= 8; i++) a[i] = read();
    int n = g();
    q.push(E);
    while(!q.empty())
    {
    	int u = q.front();
    	q.pop();
    	if(u == n) break;
    	cover(u);
    	for(int i = 1; i <= 3; i++)
    	{
    		change(i);
    		int v = g();
    		if(!dis.count(v))
    		{
    			dis[v] = dis[u] + 1;
    			q.push(v);
    			string s1 = path[u];
    			if(i == 1) s1 += 'A';
    			if(i == 2) s1 += 'B';
    			if(i == 3) s1 += 'C';
    			path[v] = s1;
    		}
    		change(i != 1 ? i + 2 : 1);
    	}
    }
    printf("%d\n", dis[n]);
    cout << path[n];
	return 0;
}

3. Knight Moves

思路:

双向bfs

如果其中一个搜索到了另一个搜到过的状态 则搜索完成 对状态进行拼接

code:

/*
  Time: 12.27
  Worker: Blank_space
  Source: #10028. 「一本通 1.4 例 3」Knight Moves
*/
/*--------------------------------------------*/
#include<cstdio>
#include<queue>
#include<string.h>
#define emm(x) memset(x, 0, sizeof x)
using namespace std; 
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int T, m, sx, sy, tx, ty;
int dx[9] = {0, 1, 1, -1, -1, 2, 2, -2, -2};
int dy[9] = {0, 2, -2, 2, -2, 1, -1, 1, -1};
struct node {
	int x, y;
};
queue <node> q1;
queue <node> q2;
int vis1[310][310], vis2[310][310];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void clear1()
{
	queue <node> q;
	swap(q, q1);
}
void clear2()
{
	queue <node> q;
	swap(q, q2);
}
void work()
{
	emm(vis1); emm(vis2); clear1(); clear2();
	m = read(); sx = read(); sy = read(); tx = read(); ty = read();
	if(sx == tx && sy == ty) {puts("0"); return ;}
	q1.push((node){sx, sy}); q2.push((node){tx, ty});
	while(!q1.empty() && !q2.empty())
	{
		if(q1.size() <= q2.size() || q2.empty())
		{
			node t = q1.front(); q1.pop();
			int x = t.x, y = t.y;
			for(int i = 1; i <= 8; i++)
			{
				int xx = x + dx[i], yy = y + dy[i];
				if(xx < 0 || xx > m || yy < 0 || yy > m || vis1[xx][yy]) continue;
				vis1[xx][yy] = vis1[x][y] + 1;
				if(vis2[xx][yy]) {printf("%d\n", vis1[xx][yy] + vis2[xx][yy]); return ;}
				q1.push((node){xx, yy});
			}
			continue;
		}
		if(q1.size() >  q2.size() || q1.empty())
		{
			node t = q2.front(); q2.pop();
			int x = t.x, y = t.y;
			for(int i = 1; i <= 8; i++)
			{
				int xx = x + dx[i], yy = y + dy[i];
				if(xx < 0 || xx > m || yy < 0 || yy > m || vis2[xx][yy]) continue;
				vis2[xx][yy] = vis2[x][y] + 1;
				if(vis1[xx][yy]) {printf("%d\n", vis1[xx][yy] + vis2[xx][yy]); return ;}
				q2.push((node){xx, yy});
			}
			continue;
		}
	}
}
/*----------------------------------------函数*/
int main()
{
    T = read();
    while(T--) work();
	return 0;
}

4. 棋盘游戏

思路:

看到题的第一想法是状压

感觉确实能做

但是状态的转移情况有点多 不是很会转移

于是推一下 看有没有别的方法

感觉这个题可以看做直接将不同的棋子移到最近的不同的位置

试一下

80 Pts

这样做是可以的 但是有一点bug:

一个棋子先搜到一个自己位置可能会占用其他棋子的最优位置 导致答案不是最优

手动改变一下搜索顺序 从外圈开始搜

100 Pts

/*
  Time: 12.27
  Worker: Blank_space
  Source: #10029. 「一本通 1.4 练习 1」棋盘游戏
*/
/*--------------------------------------------*/
#include<cstdio>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int mp1[5][5], mp2[5][5], ans;
struct node {
	int x, y;
};
int dx[5] = {0, 1, -1, 0, 0};
int dy[5] = {0, 0, 0, 1, -1};
bool vis[5][5];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void bfs(int x, int y)
{
	queue <node> q;
	q.push((node){x, y});
	while(!q.empty())
	{
		node h = q.front(); q.pop();
		int _x = h.x, _y = h.y;
		for(int i = 1; i <= 4; i++)
		{
			int xx = _x + dx[i], yy = _y + dy[i];
			if(xx < 1 || xx > 4 || yy < 1 || yy > 4) continue;
			if(!vis[xx][yy] && mp2[xx][yy])
			{
				ans += abs(xx - x) + abs(yy - y);
				vis[xx][yy] = 1; return ;
			}
			q.push((node){xx, yy});
		}
	}
}
/*----------------------------------------函数*/
int main()
{
    for(int i = 1; i <= 4; i++)
    	for(int j = 1; j <= 4; j++)
    	{
    		char c; cin >> c;
    		mp1[i][j] = c - 48;
    	}
    for(int i = 1; i <= 4; i++)
    	for(int j = 1; j <= 4; j++)
		{
			char c; cin >> c;
			mp2[i][j] = c - 48;
			if(mp1[i][j] == mp2[i][j]) vis[i][j] = 1;
		}
	for(int i = 1; i <= 4; i++) if(mp1[1][i] > mp2[1][i]) bfs(1, i);
	for(int i = 1; i <= 4; i++) if(mp1[4][i] > mp2[4][i]) bfs(4, i);
	for(int i = 1; i <= 4; i++) if(mp1[2][i] > mp2[2][i]) bfs(2, i);
	for(int i = 1; i <= 4; i++) if(mp1[3][i] > mp2[3][i]) bfs(3, i);
    printf("%d", ans);
	return 0;
}

5. Keyboarding

没做

6. 山峰和山谷

思路:

裸的bfs

一开始判重出了点问题 83 Pts

没有发现 尝试加了一个优化 78 Pts

???

弄上判重 100 Pts

/*
  Time: 12.27
  Worker: Blank_space
  Source: #2653. 「POI2007」山峰和山谷 Ridges and Valleys
*/
/*--------------------------------------------*/
#include<cstdio>
#include<string.h>
#include<queue>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, mp[1010][1010], ans1, ans2;
bool vis[1010][1010];
struct node {
	int x, y;
};
int dx[9] = {0, 0, 0, 1, 1, 1, -1, -1, -1};
int dy[9] = {0, 1, -1, 0, 1, -1, 0, 1, -1};
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void bfs(int x, int y)
{
	queue <node> q;
	q.push((node){x, y});
	int g1 = 1, d = 0;// 1 周围低于中间  2 高
	while(!q.empty())
	{
		node h = q.front(); q.pop();
		int _x = h.x, _y = h.y;
		for(int i = 1; i <= 8; i++)
		{
			int xx = _x + dx[i], yy = _y + dy[i];
			if(xx < 1 || xx > n || yy < 1 || yy > n) continue;
			if(mp[xx][yy] == mp[_x][_y] && !vis[xx][yy]) q.push((node){xx, yy}), vis[xx][yy] = 1;
			if(d == 0)
				d = mp[xx][yy] < mp[_x][_y] ? 1 : mp[xx][yy] > mp[_x][_y] ? 2 : 0;
			else if(!g1) continue;
			else if(mp[xx][yy] > mp[_x][_y] && d == 1) g1 = 0;
			else if(mp[xx][yy] < mp[_x][_y] && d == 2) g1 = 0;
		}
	}
	if(d == 1) ans1 += g1;
	if(d == 2) ans2 += g1;
	if(d == 0) ans1 = 1, ans2 = 1;
}
/*----------------------------------------函数*/
int main()
{
    n = read();
    for(int i = 1; i <= n; i++)
    	for(int j = 1; j <= n; j++) mp[i][j] = read();
    for(int i = 1; i <= n; i++)
    	for(int j = 1; j <= n; j++)
    		if(!vis[i][j])
				bfs(i, j);
	printf("%d %d", ans1, ans2);
	return 0;
}

posted @ 2020-12-27 21:24  Blank_space  阅读(58)  评论(1编辑  收藏  举报
// // // // // // //