这个题目是一个最典型的图的的遍历和图的建立
题目链接:查找文献
图论第一步!如何存储数据
我们在做这个题目的时候 我们第一时间肯定是会用邻接矩阵来做(毕竟操作更加方便)
邻接矩阵的定义:
给定你两个点 a和b 那么你可以链接他们 linker[a][b] = 1;
由此可以使得得到一个n*m的矩阵 但是由于此题数据量
先拿一波分直接考虑矩阵 代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int arr[N], idx;
int linker[N][N];
bool st[N];
int n,m, ans;
void dfs(int x) {
arr[idx++] = x;
for (int i = 1; i <= n; i++) {
if (linker[x][i] && !st[i]) {
st[i] = 1;
dfs(i);
}
}
}
void bfs(int x) {
queue<int> qu;
qu.push(1);
arr[idx++] = x;
while (qu.size()) {
auto temp = qu.front();
qu.pop();
for (int i = 1; i <= n; i++) {
if (linker[temp][i] && !st[i]) {
st[i] = 1;
arr[idx++] = i;
qu.push(i);
}
}
}
for (int i = 0; i < idx; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
cin >> n>>m;
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
linker[a][b] = 1;
}
dfs(1);
for (int i = 0; i < idx; i++) {
cout << arr[i] << " ";
}
cout << endl;
memset(st, 0, sizeof st);
idx = 0;
bfs(1);
}
闷头直接做
明显是超过了二维数组的定义区间 所以如果我们定义的话一定会超过计算机能处理的范围大小
那么应该怎么做呢?
大家可以蛮明显的想到 我们定义了一个二维数组 那么这个数组可以存N*N的边 但是我们知道 题目给的边数只有1e6的边数 那么其实整个图看上去就是很稀疏的样子 那么我们可以定义一个更好的数据结构来存储:
邻接表
邻接表的定义有很多种方法 而我第一次做这个题目的时候 我用的是Acwing里y总的模板:
const int N = 1e5+10;
int h[N],e[N],ne[N],idx;
void add(int a,int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
这是用一个类似于链表的做法做出来的一个邻接表 add就是在a->b的一条边;
那么这样的作法就能够完美的在后续的遍历中遍历每一个点的下一个边
//假设x为起点
int x;
cin>>x;
//初始化头部为-1;
memset(h,-1,sizeof h);
//遍历每一个点
for(int i = h[x];i!=-1;i = ne[i]){
int j = e[i];
}
看上去是否有点难懂(毕竟是y总写的板子 看不懂很正常 记下来用就行了)
其实事实上在这种方案当中 最后一个被添加到a下的点b一定是最先被遍历到的(可以去尝试debug理解)
看一下用这种模板写的题解:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int arr[N], ind;
int h[N], e[N], ne[N], idx;
int n, m, ans;
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int x) {
for (int i = h[x]; i != -1; i = ne[i]) {
int j = e[i];
arr[ind++] = j;
dfs(i);
}
}
void bfs(int x) {
queue<int> qu;
qu.push(1);
arr[ind++] = x;
while (qu.size()) {
auto temp = qu.front();
qu.pop();
for (int i = h[temp]; i != -1; i = ne[i]) {
int j = e[i];
arr[ind++] = j;
qu.push(i);
}
}
}
void print() {
for (int i = 0; i < ind; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
add(a, b);
}
dfs(1);
print();
ind = 0;
bfs(1);
print();
}
这种邻接表只能完成对每个节点的遍历 但是不能考虑顺序!!!
最后我们拿出正解 vector<int> linker[N];
这种数据结构完美的避开了数组容量太大的问题(自动扩容机制嘛);
最终题解:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int arr[N], idx;
vector<int> linker[N];
bool st[N];
int n, m, ans;
void dfs(int x) {
arr[idx++] = x;
for (int i = 0; i < linker[x].size(); i++) {
int j = linker[x][i];
if (!st[j]) {
st[j] = 1;
dfs(j);
}
}
}
void bfs(int x) {
queue<int> qu;
qu.push(x);
arr[idx++] = x;
while (qu.size()) {
auto temp = qu.front();
qu.pop();
for (int i = 0; i < linker[temp].size(); i++) {
int j = linker[temp][i];
if (!st[j]) {
st[j] = 1;
arr[idx++] = j;
qu.push(j);
}
}
}
for (int i = 0; i < idx; i++) {
cout << arr[i] << " ";
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
linker[a].push_back(b);
}
for (int i = 1; i <= n; i++)sort(linker[i].begin(), linker[i].end());
st[1] = 1;
dfs(1);
for (int i = 0; i < idx; i++) {
cout << arr[i] << " ";
}
cout << endl;
memset(st, 0, sizeof st);
idx = 0;
st[1] = 1;
bfs(1);
}
好像一不小心就过了呢QAQ;
备注:
这个题目主要是学到了用更好的数据结构存储图 而没有过多的讲dfs和bfs的算法了(其实是个板子 大家可以记一下)