三、多源bfs
题意:找出所有点的最短曼哈顿距离
思路:对于多源bfs来说,如果有多个相同起点的,我可以直接将所有相同起点加入到队列。从而因为层序遍历会每次把所有为1的点都遍历一遍(涉及到每一层)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1010;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
int n,m;
char mp[N][N];
int dist[N][N];
bool st[N][N];
int hr[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
void bfs()
{
memset(dist,INF,sizeof dist);
queue<PII>q;
for(int i = 0 ; i < n; i ++)
for(int j = 0;j < m; j ++)
{
if(mp[i][j] == '1')
{
q.push({i,j});
dist[i][j] = 0;
st[i][j] = 0;
}
}
while(q.size())
{
auto t = q.front();
q.pop();
for(int i = 0; i < 4; i ++)
{
int a = t.first + hr[i][0];
int b = t.second + hr[i][1];
if(a < 0 || a >= n || b < 0 || b >= m) continue;
if(st[a][b]) continue;//第一次已经搜到的点一定已经是最小,类dij
if(dist[a][b] > dist[t.first][t.second] + abs(t.first - a) + abs(t.second - b))
{
dist[a][b] = dist[t.first][t.second] + abs(t.first - a) + abs(t.second - b);
q.push({a,b});
st[a][b] = 1;
}
}
}
}
void solve()
{
cin >> n >> m;
for(int i = 0; i < n; i ++) cin >> mp[i];
bfs();
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < m; j ++)
{
if(j) cout << " ";
cout << dist[i][j];
}
cout << endl;
}
}
int main()
{
solve();
system("pause");
return 0;
}
四、最小步数模型
题意:找到可变换的最小步数
思路:
1、对于string类的bfs搜索可以用unordered_map存距离
2、同时n * n的展开可用康托展开从二维转换到一维(由二维转换到一维可以用for循环初始化数组使得二维转换成一维)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};
int n,m;
int bfs(string start)
{
string end = "12345678x";
queue<string>q;
unordered_map<string ,int> d;
q.push(start);
d[start] = 0;
while(q.size())
{
auto t = q.front();
q.pop();
int distance = d[t];
if(t == end) return distance ;
int k = t.find('x');
int x = k / 3, y = k % 3;//非常nb的一维转化成2维
for(int i = 0 ; i < 4; i ++)
{
int a = x + dx[i];
int b = y + dy[i];
if(a >= 0 && a < 3 && b >= 0 && b < 3)
{
swap(t[k],t[a * 3 + b]);
if(!d.count(t))
{
d[t] = distance + 1;
q.push(t);
}
swap(t[k],t[a * 3 + b]);
//还原这个状态,为走下一次做准备
}
}
}
return -1;
}
int main()
{
string start;
for(int i = 0; i < 9; i ++)
{
char c;
cin >> c;
start += c;
}
cout<<bfs(start)<<endl;
system("pause");
return 0;
}
思路:多种变换的八数码,按照所述进行暴搜即可
注意!:哥们间断性wa了3天才发现是从12345678变到输入而不是输入变到12345678
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<char, string >
#define PLL pair<ll, ll>
const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
string start,endt;
unordered_map<string,PII>pre;
unordered_map<string,int>dist;
string get(string s,int t)
{
string res = s;
if(t == 0) res = {s[7],s[6],s[5],s[4],s[3],s[2],s[1],s[0]};
if(t == 1) res = {s[3],s[0],s[1],s[2],s[5],s[6],s[7],s[4]};
if(t == 2) res = {s[0],s[6],s[1],s[3],s[4],s[2],s[5],s[7]};
return res;
}
void bfs(string start)
{
dist[start] = 0;
queue<string>q;
q.push(start);
while(q.size())
{
auto t = q.front();
q.pop();
if(t == endt) return;
for(int i = 0; i < 3; i ++)
{
string s = get(t,i);
if(!dist.count(s))
{
dist[s] = dist[t] + 1;
pre[s] = {char(i + 'A'),t};
if(s == endt) return;
q.push(s);
}
}
}
}
void solve()
{
for(int i = 0; i < 8; i ++)
{
char c;
cin >> c;
endt += c;
}
start = "12345678";
bfs(start);
cout << dist[endt] << endl;
string ans;
while(start != endt)
{
ans += pre[endt].first;
endt = pre[endt].second;
}
reverse(ans.begin(),ans.end());
if(ans.size()) cout << ans << endl;
}
int main()
{
solve();
system("pause");
return 0;
}