第三讲 搜索与图论

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/

点击查看代码

posted @   超级氯化钾  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示