第三讲 搜索与图论
1.DFS
AcWing 842. 排列数字
https://www.acwing.com/activity/content/problem/content/905/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int n;
bool vis[N];
int cnt[10]; //输出字符
void dfs(int idx){
if(idx == n+1){
for(int i = 1; i <= n; i++){
cout << cnt[i] << " ";
}
cout << endl;
}
for(int i = 1; i <= n; i++){
if(!vis[i]){
vis[i] = 1;
cnt[idx] = i;
dfs(idx+1);
vis[i] = 0;
}
}
}
int main(){
cin >> n;
dfs(1); //从第一个数字开始dfs
return 0;
}
AcWing 843. n-皇后问题
https://www.acwing.com/problem/content/845/
点击查看代码
#include <iostream>
using namespace std;
// n皇后,每个皇后在不同行,不同列,不在一个斜线上
// 一共摆n个皇后,那么每行都要摆一个,且只能摆一个
int n; // 1~9
char g[10][10];
bool isok(int r,int c){
for(int i = 1; i <= r-1; i++){
for(int j = 1; j <= n; j++){
if(g[i][j] == 'Q'){
if(c == j) return false; //同列
if((c-j)*(c-j) == (r-i)*(r-i)) return false; //同一斜线上
}
}
}
return true;
}
void dfs(int row){
if(row == n+1){
// output
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(g[i][j] != 'Q') cout << ".";
else cout << g[i][j];
}
cout << endl;
}
cout << endl;
}
// 枚举列的位置
for(int i = 1; i <= n; i++){
if(isok(row,i)){
g[row][i] = 'Q';
dfs(row+1);
g[row][i] = ' ';
}
}
}
int main(){
cin >> n;
dfs(1); //从第一行开始
return 0;
}
2.BFS
Acwing844 走迷宫
https://www.acwing.com/activity/content/problem/content/907/
点击查看代码
#include <iostream>
#include <queue>
#include <map>
using namespace std;
const int N = 1010;
int g[N][N];
bool vis[N][N];
int n,m; // n*m的二维数组
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
queue<pair<pair<int,int>,int> > q; // (x,y),step
bool isok(int x,int y){
if(x < 1 || x > n || y < 1 || y > m) return false;
return true;
}
int bfs(){
q.push(make_pair(make_pair(1,1),0));
vis[1][1] = 1;
while(!q.empty()){
int x = q.front().first.first;
int y = q.front().first.second;
int step = q.front().second;
if(x == n && y == m){
return step;
}
q.pop();
for(int i = 0; i < 4; i++){
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if(g[xx][yy] == 0 && !vis[xx][yy] && isok(xx,yy)) {
vis[xx][yy] = 1;
q.push(make_pair(make_pair(xx,yy),step+1));
}
}
}
return -1;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> g[i][j];
}
}
cout << bfs() << endl;
return 0;
}
3.树与图的dfs
4.树与图的bfs
AcWing 847. 图中点的层次
https://www.acwing.com/problem/content/description/849/
点击查看代码
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
//有向图
const int N = 100010,M = N + N;
int h[N],e[M],ne[M],idx;
bool vis[N];
int n,m;
void add(int a,int b){
// a节点指向b节点
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
//求出 1 号点到 n 号点的最短距离
int bfs(){
queue<pair<int,int> > q; //顶点号 + 最短距离
q.push(make_pair(1,0));
vis[1] = 1;
while(!q.empty()){
int top = q.front().first;
int dis = q.front().second;
q.pop();
if(top == n){
return dis;
}
for(int i = h[top]; i != -1; i = ne[i]){
int val = e[i];
if(!vis[val]){
vis[val] = 1;
q.push(make_pair(val,dis+1));
}
}
}
return -1;
}
int main(){
memset(h,-1,sizeof(h));
cin >> n >> m; //n个节点,m个边
int a,b;
for(int i = 1; i <= m; i++){
cin >> a >> b;
add(a,b);
}
cout << bfs() << endl;
return 0;
}
5.拓扑排序
AcWing 848. 有向图的拓扑序列
https://www.acwing.com/problem/content/850/
点击查看代码
/* ***********************************************
Author KCL
Created Time :一 3/ 7 16:58:30 2022
File Name :848有向图的拓扑序列.cpp
************************************************ */
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int h[N],e[N+N],ne[N+N],idx;
int n,m;
int d[N]; //每个节点的入度
//队列
int q[N],tt = -1,hh;
void add(int a,int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx;
idx++;
}
bool topsort(){
//入度为0的节点加入队列
for(int i = 1; i <= n; i++)
if(d[i] == 0) q[++tt] = i;
while(tt >= hh){
int t = q[hh];
hh++; //入度为0的节点必须出队列
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
d[j]--;
if(d[j] == 0) q[++tt] =j ;
}
}
//tt走到 n-1时,表示所有节点都入了队列,有拓扑排序
if(tt == n-1) return true;
return false;
}
int main(){
std::ios::sync_with_stdio(false);
memset(h,-1,sizeof(h));
cin >> n >> m;
int a,b;
while(m--){
cin >> a >> b;
add(a,b);
d[b]++; //b的入度增加
}
if(topsort()){
for(int i = 0; i <= n-1; i++) cout << q[i] << " ";
}else{
cout << -1 << endl;
}
return 0;
}
6.Dijkstra
AcWing 849. Dijkstra求最短路 I
https://www.acwing.com/problem/content/description/851/
点击查看代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
bool st[N];
int n,m;
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
for(int i = 1; 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] = 1;
for(int j = 1; j <= n; j++){
dist[j] = min(dist[j],dist[t] + g[t][j]);
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main(){
cin >> n >> m;
memset(g,0x3f,sizeof g);
while(m--){
int a,b,c; cin >> a >> b >> c;
g[a][b] = min(g[a][b],c);
}
cout << dijkstra() << endl;
return 0;
}
AcWing 850. Dijkstra求最短路 II
https://www.acwing.com/activity/content/problem/content/919/
点击查看代码
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N = 200010;
int dist[N];
bool vis[N];
int h[N],w[N],e[N],ne[N],idx;
int n,m;
void add(int a,int b,int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
typedef pair<int,int> PII;
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1}); // 1号节点,最短路为0
while(heap.size()){
auto t = heap.top();
int var = t.second;
int distance = t.first;
heap.pop();
if(!vis[var]){
vis[var] = 1;
for(int i = h[var]; i != -1; i = ne[i]){
int j = e[i]; //其他的节点
if(distance + w[i] < dist[j]){
dist[j] = w[i] + distance;
heap.push({dist[j],j});
}
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main(){
memset(h,-1,sizeof h);
cin >> n >> m;
while(m--){
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
}
cout << dijkstra() << endl;
return 0;
}
7.bellman_ford算法
AcWing 853. 有边数限制的最短路
https://www.acwing.com/problem/content/description/855/
点击查看代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510,M = 10010;
int n,k,m;
struct Edge{
int a,b,w;
}edges[M];
int dist[N],backup[N];
void bellman_ford(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
for(int i = 1; i <= k; i++){
memcpy(backup,dist,sizeof dist);
for(int i = 0; i < m; i++){
int a = edges[i].a,b = edges[i].b,w = edges[i].w;
if(backup[a] + w < dist[b]){
dist[b] = min(dist[b],backup[a] + w);
}
}
}
if(dist[n] > 0x3f3f3f3f/2){
cout << "impossible" << endl;
}else{
cout << dist[n] << endl;
}
}
int main(){
cin >> n >> m >> k;
for(int i = 0; i < m; i++){
int a,b,w; cin >> a >> b >> w;
edges[i] = {a,b,w};
}
bellman_ford();
return 0;
}
8.spfa算法
AcWing 851. spfa求最短路(超时)
https://www.acwing.com/activity/content/problem/content/920/
点击查看代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000010;
int dist[N],st[N];
int h[N],w[N*2],e[N*2],ne[N*2],idx;
int n,m;
int q[N],tt = -1,hh;
void add(int a,int b,int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int spfa(){
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
st[1] = 1; //1号节点即将更新
q[++tt] = 1;
while(tt >= hh){
int var = q[hh];
hh++;
st[var] = 0; // var节点已经更新
for(int i = h[var]; i != -1; i = ne[i]){
int j = e[i];
if(dist[var] + w[i] < dist[j]){
q[++tt] = j;
dist[j] = dist[var] + w[i];
st[j] = 1; // j节点可以更新其他的节点
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main(){
memset(h,-1,sizeof h);
cin >> n >> m;
while(m--){
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
}
int t = spfa();
if(t == -1) cout << "impossible" << endl;
else cout << t << endl;
return 0;
}
AcWing 852. spfa判断负环
https://www.acwing.com/activity/content/problem/content/921/
点击查看代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律