Acwing算法基础课-搜索与图论-模板习题

目录

一、DFS

1.排列数字

2.n-皇后问题

二、BFS

1.走迷宫

2.八数码

二、树与图的深度优先遍历DFS

树的重心

三、树与图的广度优先遍历BFS

图中点的层次

四、拓扑排序

有向图的拓扑序列

五、Dijkstra

1.Dijkstra求最短路I(朴素)

2.Dijkstra求最短路II(堆优化)

六、bellman-ford

有边数限制的最短路

七、spfa

1.spfa求最短路

2.spfa判断负环

八、Floyd

Floyd求最短路(多源汇最短路问题)

九、Prim

Prim算法求最小生成树

十、Kruskal

Kruskal算法求最小生成树

十一、染色法判定二分图

染色法判断二分图

十二、匈牙利算法

二分图的最大匹配


一、DFS

1.排列数字

842. 排列数字 - AcWing题库https://www.acwing.com/problem/content/844/

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 3e5 + 5;
int path[N];
bool state[N];
int n;

void dfs(int u){
    // 输出方案
    if(u > n){
        for(int i = 1; i <= n; i ++) cout << path[i] << ' ';
        cout << '\n';
    }
    
    for(int i = 1; i <= n; i ++){
        // 数字i未被使用
        if(!state[i]){
            path[u] = i;
            state[i] = true;
            dfs(u + 1);
            // 回溯 取出i
            state[i] = false;
        }
    }
}

void solve(){
    cin >> n;
    dfs(1);
}

signed main(){
    sync;
    
    solve();
}

2.n-皇后问题

843. n-皇后问题 - AcWing题库https://www.acwing.com/problem/content/845/

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 3e2 + 5;
char res[N][N];
//    列,对角线,反对角线状态
bool c[N], d[N], ud[N];
int n;

void dfs(int r){
    // 最后一行 输出答案
    if(r == n){
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < n; j ++){
                cout << res[i][j];
            }
            cout << '\n';
        }
        cout << '\n';
    }
    
    //第r行
    for(int i = 0; i < n; i ++){
        if(!c[i] && !d[i + r] && !ud[n - i + r]){
            res[r][i] = 'Q';
            c[i] = d[i + r] = ud[n - i + r] = true;
            dfs(r + 1);
            //回溯
            c[i] = d[i + r] = ud[n - i + r] = false;
            res[r][i] = '.';
        }
    }
}

void solve(){
    cin >> n;
    for(int i = 0; i < n; i ++){
        for(int j = 0; j < n; j ++){
            res[i][j] = '.';
        }
    }
    dfs(0);
}

signed main(){
    sync;
    
    solve();
}

二、BFS

1.走迷宫

844. 走迷宫 - AcWing题库https://www.acwing.com/problem/content/846/

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef pair <int, int> PII;
const int N = 110;
int ma[N][N]; // 地图
int d[N][N]; // 距离
int n, m;

void bfs(int a, int b){
    queue <PII> q;
    q.push({a, b});
    while(!q.empty()){
        PII start = q.front();
        q.pop();
        ma[start.first][start.second] = 1;
        // 四个方向的偏移量
        int dx[4] = {0, 1, 0, -1};
        int dy[4] = {-1, 0, 1, 0};
        // 往四个方向走
        for(int i = 0; i < 4; i ++){
            int x = start.first + dx[i];
            int y = start.second + dy[i];
            // 走没走过的地方
            if(x > 0 && x <= n && y > 0 && y <= m && ma[x][y] == 0){
                ma[x][y] = 1;
                // 从当前点走过 距离+1
                d[x][y] = d[start.first][start.second] + 1;
                q.push({x, y});
            }
        }
    }
    cout << d[n][m];
}

void solve(){
    cin >> n >> m;
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            cin >> ma[i][j];
        }
    }
    bfs(1, 1);
}

signed main(){
    sync;
    
    solve();
}

2.八数码

845. 八数码 - AcWing题库https://www.acwing.com/problem/content/847/

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define sync ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef pair <int, int> PII;
const int N = 3e5 + 5;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};

void bfs(string s){
    string end = "12345678x";       // 目标状态
    queue <string> q;               // 队列q存储状态
    unordered_map <string, int> d;  // d存储状态与距离的关系
    
    q.push(s);                      // 初始状态 
    d[s] = 0;
    while(q.size()){
        string t = q.front();
        q.pop();
        
        int dist = d[t];
        if(t == end){
            cout << dist << '\n';
            return;
        }
        else{
            // 状态转移
            int k = t.find('x');
            // 图和字符串的关系
            int x = k/3;
            int y = k%3;
            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) == 0){
                        d[t] = dist + 1;
                        q.push(t);
                    }
                    // 状态回溯
                    swap(t[k], t[a*3 + b]);
                }
            }
        }
    }
    cout << "-1\n";
}

void solve(){
    string s;
    // 将3*3的图转化成字符串处理
    for(int i = 0; i < 9; i ++){
        string x;
        cin >> x;
        s += x;
    }
    bfs(s);
}

signed main(){
    sync;
    
    solve();
}

二、树与图的深度优先遍历DFS

树的重心

846. 树的重心 - AcWing题库https://www.acwing.com/problem/content/848/

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
const int M = N * 2;		// 以有向图形式存储无向图 每个节点最多2N-2条边
int h[N], e[M], ne[M], idx;	// 邻接表存图
int n, res = INF;
bool st[N];		// 记录节点访问状态

// 以a为根 插入b
void add(int a, int b){
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

// 求以u为根的子树节点数
int dfs(int u){
	st[u] = 1;
	int cnt = 0;	// cnt记录以u为重心的子树节点最大值
	int sum = 1;	// sum记录以u为重心的子树节点数 初始含u为1
	for(int i = h[u]; i != -1; i = ne[i]){
		int j = e[i];
		if(!st[j]){
			int size = dfs(j);	// 以u为根的子树节点数
			cnt = max(cnt, size);
			sum += size;
		}
	}
	// n-num则为整颗树减去以u为根的子树剩下的节点数
	cnt = max(cnt, n - sum);
	res = min(res, cnt);
	return sum;
}

int solve(){
	memset(h, -1, sizeof h);
	
	cin >> n;
	for(int i = 0; i < n - 1; i ++){
		int a, b;
		cin >> a >> b;
		add(a, b);
		add(b, a);
	}
	
	dfs(1);
	return res;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
//		solve();
		cout << solve() << '\n';
	}
}

三、树与图的广度优先遍历BFS

图中点的层次

847. 图中点的层次 - AcWing题库https://www.acwing.com/problem/content/849/

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int e[N], h[N], ne[N], idx;	// 邻接表存有向图
int dist[N];
int n, m;

void add(int a, int b){
	e[idx] = b; ne[idx] = h[a], h[a] = idx ++;
}

int bfs(){
	memset(dist, -1, sizeof dist);	// 初始化距离
	
	queue <int> q;
	q.push(1);
	dist[1] = 0;	//到自己的距离为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(dist[j] == -1){
				dist[j] = dist[t] + 1;	// 更新距离
				q.push(j);
			}
		}
	}
	return dist[n];
}

int solve(){
	memset(h, -1, sizeof h);
	
	cin >> n >> m;
	while(m --){
		int a, b;
		cin >> a >> b;
		add(a, b);
	}
	return bfs();
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
//		solve();
		cout << solve() << '\n';
	}
}

四、拓扑排序

有向图的拓扑序列

848. 有向图的拓扑序列 - AcWing题库https://www.acwing.com/problem/content/850/

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int e[N], h[N], ne[N], idx;
int n ,m;
int d[N];	//存储各点的入度值
int res[N];

void add(int a, int b){
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void topsort(){
	queue <int> q;
	idx = 0;
	for(int i = 1; i <= n; i ++){
		if(d[i] == 0){
			q.push(i);
			res[idx ++] = i;
		}
	}
	
	while(q.size()){
		int t = q.front();
		q.pop();
		for(int i = h[t]; i != -1; i = ne[i]){	//遍历入度为0的点指向的点
			int j = e[i];
			d[j] --;	// 删除t指向j的边 j的入度减1
			if(d[j] == 0){
				q.push(j);
				res[idx ++] = j;
			}
		}
	}

	if(idx == n){	// n个点都满足则该有向图为拓扑序列
		for(int i = 0; i < idx; i ++) cout << res[i] << ' ';
	}
	else cout << -1;
}

void solve(){
	memset(h, -1, sizeof h);
	
	cin >> n >> m;
	while(m --){
		int a, b;
		cin >> a >> b;
		add(a, b);
		d[b] ++;
	}
	topsort();
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

五、Dijkstra

1.Dijkstra求最短路I(朴素)

849. Dijkstra求最短路 I - AcWing题库https://www.acwing.com/problem/content/851/

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 5e2 + 5;
int n, m;	 	// 节点数 边数
int g[N][N];	// 邻接矩阵存图
int dist[N];	// 存储距离
bool state[N];	// 存储更新状态

int dijkstra(){
	memset(dist, 0x3f, sizeof dist); // 初始化距离为无穷大
	dist[1] = 0; // 1号点到本身距离为0
	// 循环n次 找到路径最短的点
	for(int i = 0; i < n; i ++){
		// 找未更新的、距离1号点最近的点
		int t = -1;
		for(int j = 1; j <= n; j ++){
			if(!state[j] && (t == -1 || dist[t] > dist[j])) t = j;
		}
		state[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 solve(){
	cin >> n >> m;
	
	memset(g, 0x3f, sizeof g);
	while(m --){
		int a, b, x;
		cin >> a >> b >> x;
		g[a][b] = min(g[a][b], x);
	}
	
	return dijkstra();
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
//		solve();
		cout << solve() << '\n';
	}
}

2.Dijkstra求最短路II(堆优化)

850. Dijkstra求最短路 II - AcWing题库https://www.acwing.com/problem/content/852/

#include <bits/stdc++.h>
using namespace std;

//#define int long long		// 开long long会出错
#define fi first
#define se second
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;

int n, m;	   // 节点数 边数
int h[N], w[N], e[N], ne[N], idx; //邻接表建图
int dist[N];   // 距离
bool state[N]; // 状态

void add(int a, int b, int x){
	e[idx] = b, w[idx] = x, ne[idx] = h[a], h[a] = idx ++;
}

int dijkstra(){
	memset(dist, 0x3f, sizeof dist); // 距离初始化为无穷大
	dist[1] = 0; // 到本身的距离为0
	priority_queue <PII, vector <PII>, greater <PII>> heap; // 小根堆优化找dist最小值 pair <dist, 节点编号>
	heap.push({0, 1});
	
	while(heap.size()){
		PII t = heap.top();
		heap.pop();
		int k = t.se, d = t.fi;
		
		if(state[k]) continue; // 到当前节点距离已确定
		state[k] = 1; 
		
		for(int i = h[k]; i != -1; i = ne[i]){
			int j = e[i];
			int di = d + w[i];
			if(di < dist[j]){	// 更新最短距离
				dist[j] = di;
				heap.push({di, j});
			}
		}
	}
	
	if(dist[n] == INF) return -1;
	return dist[n];
}

int solve(){
	cin >> n >> m;
	
	memset(h, -1, sizeof h);
	while(m --){
		int a, b, x;
		cin >> a >> b >> x;
		add(a, b, x);
	}
	
	return dijkstra();
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
//		solve();
		cout << solve() << '\n';
	}
}

六、bellman-ford

有边数限制的最短路

853. 有边数限制的最短路 - AcWing题库https://www.acwing.com/problem/content/855/

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 5e2 + 5;
const int M = 2e5 + 5;
struct edge{
	int a, b, w;
}e[M];
int dist[N], back[N];
int n, m, k;
/*
 *Bellman-ford算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。
 *其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在 n-1 次松弛后还能更新,
 *则说明图中有负环,因此无法得出结果,否则就完成。
 *通俗的来讲就是:假设1号点到n号点是可达的,每一个点同时向指向的方向出发,更新相
 *邻的点的最短距离,通过循环n-1次操作,若图中不存在负环,则1号点一定会到达 n 号点,
 *若图中存在负环,则在 n-1 次松弛后一定还会更新。
 */
bool bellman_ford(){
	memset(dist, INF, sizeof dist);
	dist[1] = 0;
	while(k --){
		memcpy(back, dist, sizeof dist); // 备份数组防止串联情况
		for(int i = 0; i < m; i ++){
			int a = e[i].a, b = e[i].b, w = e[i].w;
			dist[b] = min(dist[b], back[a] + w); // 松弛每个点到起点距离
		}
	}
	if(dist[n] > INF / 2) return 0;
	return 1;
}

void solve(){
	cin >> n >> m >> k;
	for(int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		e[i] = {a, b, w};
	}
	if(bellman_ford()) cout << dist[n] << '\n';
	else cout << "impossible\n";
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

七、spfa

1.spfa求最短路

851. spfa求最短路 - AcWing题库https://www.acwing.com/problem/content/853/

#include <bits/stdc++.h>
using namespace std;

// #define int long long	// 开long long会出错
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
int h[N], e[N], w[N], ne[N], idx;
int dist[N];
bool state[N];
int n, m;

void add(int a, int b, int x){
	e[idx] = b; w[idx] = x; ne[idx] = h[a]; h[a] = idx ++;
}

bool spfa(){
	memset(dist, INF, sizeof dist);
	dist[1] = 0;
	queue <pair <int, int>> q;	// 记录当前发生过更新的点 state[]可逆
	q.push({0, 1});
	
	state[1] = 1;
	while(q.size()){	// spfa仅适用无负权回路
		pair <int, int> t = q.front();
		q.pop();
		int k = t.second;
		
		state[k] = 0;	//标记为false 如果发生更新则可以入队
		for(int i = h[k]; i != -1; i = ne[i]){
			int j = e[i];
			int di = dist[k] + w[i];
			if(di < dist[j]){ // 更新最短距离
				dist[j] = di;
				if(!state[j]){
					state[j] = 1;
					q.push({dist[j], j});
				}
			}
		}
	}
	if(dist[n] == INF) return 0;
	return 1;
}

void solve(){
	memset(h, -1, sizeof h);
	
	cin >> n >> m;
	while(m --){
		int a, b, x;
		cin >> a >> b >> x;
		add(a, b, x);
	}
	if(spfa()) cout << dist[n] << '\n';
	else cout << "impossible\n";
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
// 	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

2.spfa判断负环

852. spfa判断负环 - AcWing题库https://www.acwing.com/problem/content/854/

#include <bits/stdc++.h>
using namespace std;

 #define int long long
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
int h[N], e[N], w[N], ne[N], idx;
int dist[N], cnt[N];	// cnt[x] 表示当前从1~x的最短路的边数
bool state[N];
int n, m;

void add(int a, int b, int x){
	e[idx] = b; w[idx] = x; ne[idx] = h[a]; h[a] = idx ++;
}
/*
 *求负环一般使用SPFA算法 方法是用一个cnt数组记录每个点到源点的边数
 *一个点被更新一次就+1 一旦有点的边数达到了n那就证明存在了负环
 */
bool spfa(){
//	memset(dist, INF, sizeof dist); // 无需初始化 因若存在负环 无论dist初始值都会被更新

	queue <int> q; // 所有点都有可能有负环 均入队
	for(int i = 1; i <= n; i ++){
		q.push(i);
		state[i] = 1;
	}

	while(q.size()){
		auto t = q.front();
		q.pop();
		state[t] = 0;
		
		for(int i = h[t]; i != -1; i = ne[i]){
			int j = e[i];
			int di = dist[t] + w[i];
			if(di < dist[j]){
				dist[j] = di;
				cnt[j] = cnt[t] + 1;
				if(cnt[j] >= n) return 1; // 经过超过n-1条边 存在负环
				if(!state[j]){
					state[j] = 1;
					q.push(j);
				}
			}
		}
	}
	return 0;
}

void solve(){
	memset(h, -1, sizeof h);
	
	cin >> n >> m;
	while(m --){
		int a, b, x;
		cin >> a >> b >> x;
		add(a, b, x);
	}
	if(spfa()) cout << "Yes\n";
	else cout << "No\n";
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
// 	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

八、Floyd

Floyd求最短路(多源汇最短路问题)

854. Floyd求最短路 - AcWing题库https://www.acwing.com/problem/content/856/

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e2 + 5;
int n, m, k;
int d[N][N];
/*
 *状态表示:f[k][i][j]表示经过前k个点从i到j的距离
 *状态转换:f[k-1][i][j]表示不经过k从i到j  
 *			f[k - 1][i][k] + f[k - 1][k][j]表示经过k从i到j
 *状态转移方程:d[i][j] = min(d[i][j],d[i][k] + d[k][j])
 */
void floyd(){
	for(int k = 1; k <= n; k ++){
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
			}
		}
	}
}

int solve(){
	cin >> n >> m >> k;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			if(i == j) d[i][j] = 0;
			else d[i][j] = INF;
		}
	}
	while(m --){
		int a, b, x;
		cin >> a >> b >> x;
		d[a][b] = min(d[a][b], x);
	}
	floyd();
	while(k --){
		int x, y;
		cin >> x >> y;
		if(d[x][y] > INF / 2) cout << "impossible\n";
		else cout << d[x][y] << '\n';
	}
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
	cin >> t;
	while(t --){
//		solve();
		cout << solve() << '\n';
	}
}

九、Prim

Prim算法求最小生成树

#include <bits/stdc++.h>
using namespace std;

// #define int long long
const int INF = 0x3f3f3f3f;
const int N = 5e2 + 5;
int g[N][N];	// 邻接表存稠密图
int d[N], p[N]; // d[]存各点到生成树的距离	p[]为各节点的前去节点
bool state[N];  // 存储节点是否被加入生成树的状态
int n, m;

void prim(){
	memset(d, INF, sizeof d);
	d[1] = 0;
	int res = 0;
	// 循环n次找出一个点加入生成树
	for(int i = 0; i < n; i ++){
		int t = -1;
		for(int j = 1; j <= n; j ++){
			// 选择不在树中且到树的距离最短的点
			if(!state[j] && (t == -1 || d[j] < d[t])) t = j;
		}
		// 判断该点是否孤立
		if(d[t] == INF){
			cout << "impossible\n";
			return;
		}
		
		state[t] = 1;
		res += d[t];
		// 更新生成树外的点到生成树的距离
		for(int i = 1; i <= n; i ++){
			if(!state[i] && d[i] > g[t][i]){
				d[i] = g[t][i];
				p[i] = t;
			}
		}
	}
	cout << res << '\n';
}

void getPath(){
	// 共n-1条边
	for(int i = n; i > 1; i --) cout << i << ' ' << p[i] << '\n';
}

void solve(){
	memset(g, INF, sizeof g);
	cin >> n >> m;
	while(m --){
		int a, b, x;
		cin >> a >> b >> x;
		g[a][b] = g[b][a] = min(g[a][b], x);
	}
	prim();
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
// 	cin >> t;
	while(t --){
		solve();
// 		cout << solve() << '\n';
	}
}

十、Kruskal

Kruskal算法求最小生成树

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int p[N];
int n, m;
int res, cnt; // res记录生成树的树边权重之和 cnt记录全部加入到树的(多个)集合中边的数量
struct edge{
	int a, b, w;
}e[N];
// 按边的权重升序排序
bool cmp(edge a, edge b){
	return a.w < b.w;
}

int find(int x){
	return x == p[x] ? x : (p[x] = find(p[x]));
}

void kruskal(){
	for(int i = 0; i < m; i ++){
		int a = e[i].a, b = e[i].b, w = e[i].w;
		// a、b节点在不同集合才将a-b边加入生成树中
		if(find(a) != find(b)){
			p[find(a)] = p[find(b)];
			cnt ++;
			res += w;
		}
	}
	if(cnt == n - 1) cout << res << '\n'; // n-1条边可以生成n个节点的树
	else cout << "impossible\n";
}

void solve(){
	cin >> n >> m;
	for(int i = 0; i < n; i ++) p[i] = i;
	for(int i = 0; i < m; i ++){
		int a, b, w;
		cin >> a >> b >> w;
		e[i] = {a, b, w};
	}
	sort(e, e + m, cmp);
	kruskal();
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
// 	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

十一、染色法判定二分图

染色法判断二分图

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int h[N], e[N], ne[N], idx; // 邻接表存图
int color[N]; // 存储各点颜色状态 0 1 2分别表示未染色 红色 蓝色
int n, m;

void add(int a, int b){
	e[idx] = b; ne[idx] = h[a]; h[a] = idx ++;
}

bool dfs(int u, int c){
	color[u] = c;	// 染色
	
	for(int i = h[u]; i != -1; i = ne[i]){
		int t = e[i];
		if(!color[t]){	// 相邻的点未染色
			if(!dfs(t, 3 - c)) return 0;	//处理相邻点 2 <- 1, 1 <- 2
		}
		// 相邻点染色状态与u冲突
		else if(color[t] && color[t] != 3 - c) return 0;
	}
	return 1;
}

void solve(){
	memset(h, -1, sizeof h);
	
	cin >> n >> m;
	for(int i = 1; i <= m; i ++){
		int a, b;
		cin >> a >> b;
		add(a, b); add(b, a);
	}
	for(int i = 1; i <= n; i ++){
		if(!color[i]){
			if(!dfs(i, 1)){
				cout << "No\n";
				return;
			}
		}
	}
	cout << "Yes\n";
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
// 	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

十二、匈牙利算法

二分图的最大匹配

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;
int h[N], e[N], ne[N], idx; // 邻接表存图
int n1, n2, m;
bool state[N];	// 匹配状态
int match[N];	// 表示相匹配的点

void add(int a, int b){
	e[idx] = b; ne[idx] = h[a]; h[a] = idx ++;
}

int find(int x){
	// 遍历能够匹配的点
	for(int i = h[x]; i != -1; i = ne[i]){
		int j = e[i];
		if(!state[j]){	// 找到预计情况下未匹配的点相匹配
			state[j] = 1;
			if(!match[j] || find(match[j])){ // 该点确实未匹配则与之匹配
				match[j] = x;
				return 1;
			}
		}
	}
	return 0;
}

void solve(){
	memset(h, -1, sizeof h);
	
	cin >> n1 >> n2 >> m;
	while(m --){
		int a, b;
		cin >> a >> b;
		add(a, b);	
	}
	
	int res = 0;
	for(int i = 1; i <= n1; i ++){
		// 每次模拟匹配的预定情况不一样 均需初始化
		memset(state, 0, sizeof state);
		if(find(i)) res ++;
	}
	cout << res << '\n';
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	
	int t = 1;
//	cin >> t;
	while(t --){
		solve();
//		cout << solve() << '\n';
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值