关于 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;
}