洛谷题单 -- 图论的简单入门

B3643 图的存储

链接 :

图的存储 - 洛谷

思路 :

这一题要考察图的存储方式 , 一般可以使用邻接矩阵 或 邻接表来存储 图的结点 和1 边的信息 ,详情请看代码 :

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 1010 ;
int n , m ;
int a[N][N] ; // 邻接矩阵 
vector<int> b[N]; // 邻接表 

// 邻接矩阵的输出 
void pa(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout << a[i][j] << " ";
		}
		cout << endl ;
	}
}

// 邻接表的输出 
void pb(){
	for(int i=1;i<=n;i++){
		int d = b[i].size();
		cout << d << " ";
		sort(b[i].begin(),b[i].end());
		for(int j=0;j<d;j++){
			cout << b[i][j] << " ";
		}
		cout << endl ;
	}
}

int main(){
	cin >> n >> m;
	for(int i=0;i<m;i++){
		int x , y ; cin >> x >> y ;
		a[x][y] = 1 ; a[y][x] = 1 ; // 邻接矩阵
		b[x].push_back(y) ; b[y].push_back(x) ; // 邻接表 
	}
	pa();
	pb();
	return 0 ;
}

P5318 【深基18.例3】查找文献

链接

【深基18.例3】查找文献 - 洛谷

思路 :

这题考察有向图的 dfs 和 bfs ,详情请看代码,如果用邻接矩阵的话一定会mle,只能够使用邻接表,我这里采用的是用vector数组实现的邻接表,详情请看代码 :

代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10 ;
typedef long long LL ;

int n , m , x , y;
bool b[N] ; // 状态记录数组 
vector<int> a[N] ; // 邻接表 
queue<int> q;

inline int read(){//二进制优化的快读 
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}

// x指当前遍历到的结点,r表示已遍历过的结点 
void dfs(int x , int r){ 
	b[x] = true ;
	cout << x << " " ; // 输出
	if(r == n) return ;
	for(int i=0;i<a[x].size();i++){
		if(!b[a[x][i]])
			dfs(a[x][i],r+1);
	}
}

void bfs(int x){
	memset(b , false , sizeof(b)) ; // 清空bool数组
	b[x] = true ;
	q.push(x) ;
	while(!q.empty()){ // 还有没有没访问的 
		int v = q.front();
		q.pop() ; // 弹出队头 , 否则会一直在第一层遍历
		cout << v << " " ;
		for(int i=0;i<a[v].size();i++){
			if(!b[a[v][i]]){
				b[a[v][i]] = true ;
				q.push(a[v][i]);
			}
		} 
	}
}

int main(){
	// n = read() ; m = read() ;
	cin >> n >> m ;
	for(int i=1;i<=m;i++){
		x = read() ; y = read() ; 
		// cin >> x >> y ; 
		a[x].push_back(y);
	}
	for(int i=1;i<=n;i++) sort(a[i].begin(),a[i].end()); // 将每条路通向的点从小到大排序 
	dfs(1,0) ; // 深搜 
	puts("");
	for(int i=1;i<=n;i++) b[i] = false ;
	bfs(1) ; // 宽搜  
	puts("") ;
	return 0;
}

B3644 【模板】拓扑排序 / 家谱树

链接 :

https://www.luogu.com.cn/problem/B3644

思路 :

给出案例画图如下 :

拓扑排序(模板题)

代码 :

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 102 ;

vector<int> a[N] ;
int tp[N] ; // 存放拓扑序列 
int  d[N] ; // 存放每个结点的入度 
int n , x ;

bool toposort() {
	queue<int> q;
	int tt = 0 ;

	for(int i = 1; i <= n; i++) {
		if(d[i] == 0) {
			q.push(i); // 将入度为 0 的点全放进来 
		}
	}
	
	while(!q.empty()) {
		int u = q.front() ; q.pop();
		tp[++tt] = u ;
		for(auto v : a[u]) {
			d[v] -- ;
			if(d[v] == 0){
				q.push(v);
			}
		}
	}
	return tt == n;	
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		while(cin >> x){
			if(x == 0) break;
			a[i].push_back(x);
			d[x] ++;
		}
	}	
	
	if(toposort()) {
		for(int i=1;i<=n;i++){
			cout << tp[i] << " ";
		}
		cout << endl ;
	}
	else{
		return 0;
	}
	return 0 ;
}

或者说这样 :

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 102 ;

vector<int> a[N] ;
int  d[N] ; // 存放每个结点的入度 
int n , x ;

bool toposort() {
	queue<int> q;
	vector<int> res;
	
	for(int i = 1; i <= n; i++) {
		if(d[i] == 0) {
			q.push(i); // 将入度为 0 的点全放进来 
		}
	}
	
	while(!q.empty()) {
		int u = q.front() ; q.pop();
		res.push_back(u);
		for(auto v : a[u]) {
			d[v] -- ;
			if(d[v] == 0){
				q.push(v);
			}
		}
	}
	if(res.size()==n) {
		for(auto x : res) cout << x << " ";
		return true;
	}else {
		return false;
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		while(cin >> x){
			if(x == 0) break;
			a[i].push_back(x);
			d[x] ++;
		}
	}	
	
	if(toposort()) {
		return 0 ;
	}
	return 0 ;
}

P3916 图的遍历

链接 :

图的遍历 - 洛谷

思路 :

反向建边 + dfs :

代码 :

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

const int N = 1e5 + 10 ;
vector<int> g[N] ;
int n , m ;
int ans[N] ;
// 反向建图 + dfs
// 考虑较大的点能够法相到达那一些点 

void dfs(int i , int b){
	if(ans[i]) return  ;
	ans[i] = b ;
	for(int j=0;j<g[i].size();j++){
		dfs(g[i][j] , b) ;
	}
}

int main(){
	cin >> n >> m ;
	for(int i=0;i<m;i++){
		int x , y ; cin >> x >> y ;
		 g[y].push_back(x) ; // 反向建边 
	}
	for(int i=n;i;i--) dfs(i,i) ; // 对i进行dfs 
	for(int i=1;i<=n;i++){
		cout << ans[i] << " " ;
//		if(ans[i]) cout << ans[i] << endl ;
//		else cout << i << endl ;
	}  
	return 0;
}
相关推荐
sp_fyf_202434 分钟前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
香菜大丸1 小时前
链表的归并排序
数据结构·算法·链表
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
oliveira-time1 小时前
golang学习2
算法
南宫生2 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步3 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
Ni-Guvara3 小时前
函数对象笔记
c++·算法
泉崎3 小时前
11.7比赛总结
数据结构·算法
你好helloworld3 小时前
滑动窗口最大值
数据结构·算法·leetcode
AI街潜水的八角4 小时前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习