目录
一、深度优先搜索
看完效果图后感觉是不是挺通俗易懂的?好,我们来看看 DFS 的模板。
dfs(int u)
{
if(找到了||走不下去了)
{
return;
}
开始下一个情况(dfs(u+1));
}
📸实际问题
我们来看看一个经典的问题——n皇后问题。我们先来看看题目。
我们来看看代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 20;
int n;
char g[N][N];
int l[N],ug[N],ng[N];
void dfs(int u)
{
if(u == n)
{
for(int i = 0; i < n; i ++)
{
cout << g[i] << endl;
}
cout << endl;
return ;
}
for(int i = 0; i < n; i ++)
{
if(!l[i] && !ug[i + u] && !ng[i - u + n])
{
g[u][i] = 'Q';
l[i] = ug[i + u] = ng[i - u + n] = 1;
dfs(u + 1);
l[i] = ug[i + u] = ng[i - u + n] = 0;
g[u][i] = '.';
}
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < n; j ++)
{
g[i][j] = '.';
}
}
dfs(0);
return 0;
}
二、广度优先搜索
我们先来看看效果图
我们来看看模板
queue<int> q;
st[0] = true; // 表示1号点已经被遍历过
q.push(0);
while (q.size())
{
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (!s[j])
{
st[j] = true; // 表示点j已经被遍历过
q.push(j);
}
}
}
📸实际问题
来看看代码
#include <iostream>
#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1000 + 10;
int n;
typedef pair<int,int> PII;
PII q[N * N];
bool st[N][N];
char g[N][N];
int dx[4] = {-1, 0, 1, 0},dy[4] = {0, 1, 0, -1};
void bfs(int sx, int sy, int &tl, int &bd)
{
int tt = 0,hh = 0;
st[sx][sy] = true;
q[0] = {sx, sy};
while(hh <= tt)
{
PII t = q[hh ++];
tl ++;
bool is_bd = false;
for(int i = 0; i < 4; i ++)
{
int x = t.x + dx[i],y = t.y + dy[i];
if(x < 0 || x >= n || y < 0 || y >= n || st[x][y]) continue;
if(g[x][y] == '.')
{
is_bd = true;
continue;
}
st[x][y] = true;
q[++ tt] = {x, y};
}
if(is_bd) bd++;
}
}
int main(){
cin >> n;
for(int i = 0;i < n;i++) cin >> g[i];
int cnt = 0;
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
{
if(!st[i][j] && g[i][j] == '#')
{
int tl = 0,bd = 0;
bfs(i, j, tl, bd);
if(tl == bd) cnt ++;
}
}
cout << cnt << endl;
return 0;
}
那么下面我们要讲的两大算法就是与最小生成树有关的。
三、prim 算法
算法模板
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
dist[1] = 0;
for(int i = 0; i < n; i ++)
{
int t = -1;
for(int j = 1; j <= n; j ++)
if(!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
st[t] = true;
res += dist[t];
for(int j = 1; j <= n; j ++)
if(dist[j] > g[t][j] && !st[i])
{
dist[j] = g[t][j];
pre[j] = t;
}
}
return res;
}
📸实际题目
这里我们看到上面的效果图,我们可以构成一组数据,如果这组数据没有输出 impossible,那么它存在最小生成树。
9 16
0 1 8
0 2 12
1 4 9
1 3 25
1 2 13
2 6 21
2 3 14
2 6 12
3 5 8
3 7 12
3 8 16
4 5 19
4 3 20
5 7 11
7 8 6
6 8 11
四、Kruskal算法
📸实际题目
同样是上面的题目与数据
我们来看看代码是如何实现的。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n,m;
struct Edge
{
int u, v, w;
bool operator<(const Edge &a) const
{
return w<a.w;
}
}edge[N];
int p[N];
int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
int main()
{
int n, m;
scanf("%d%d",&n, &m);
for(int i=0;i<m;i++)
{
int u, v, w;
scanf("%d%d%d",&u, &v, &w);
edge[i] = {u,v,w};
}
sort(edge, edge + m);
for(int i = 1; i <= n; i ++) p[i] = i;
int cnt = 0, sum = 0;
for(int i = 0; i < m; i ++)
{
int a = edge[i].u, b=edge[i].v, w = edge[i].w;
a = find(a);
b = find(b);
if(a != b)
{
cnt ++;
sum += w;
p[a] = b;
}
}
if(cnt < n - 1) puts("impossible");
else printf("%d", sum);
}
用同样的数据,不同的算法得到相同的结果,没毛病。
五、小结
我们来看看时间复杂度的分析
快期末了,接下来的时间会比较紧,更新频率可能会比以前低了,见谅解🤝。
(求关注)持续更新中……