加载中...

信息奥赛|图论基础与搜索


信息奥赛|图论基础与搜索

图论基础 简介 🚀

图论是信息奥赛中的重要内容。

图论中有不少 术语 需要掌握。

https://blog.csdn.net/raelum/article/details/129108365

图 是一个由点集 V = { v 1, v 2, · · · , v n} 和边集 E = { e 1, e 2, · · · , e m} 构成的结构.

一张图是连通图 ⇔ ∀v i, v j, i = ̸ j,∃ 一个首尾相连的边集 { e k1, e k2, · · · , e kt} , s.t. e k 1 = vi ,e k t = vj .

没有重边和自环的图称为简单图

有向图 & 无向图 若一张图的边集中的元素为有序对, 则这张图称为有向图; 反之则称为无 向图.

度 (degree) 与一个点相连的边的条数称为这个点的度. 特别地, 在有向图中, 指向一个点的 边的条数称为这个点的入度, 指向反向的边的条数称为这个点的出度, 出度加入度等于度. 可以证明在一张图中, 所有点的度数之和为偶数.


图(Graph)详解 ☘️

图的建立

图的建立方式一般有以下几种

  • 邻接表(Vector)
  • 邻接表(链式前向星)
  • 邻接矩阵

无权图 - vector 存储

#include<bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;  // 最大顶点数量
vector<int> g[N];  // vector存储无权图

// 添加一条无权有向边:u -> v
void add_edge(int u, int v) {
    g[u].push_back(v); // 假设g[1]={2, 3},表示存在边:1->2、1->3
}

int main() {
		// 读取边的数量
    int n, x, y;
    cin >> n;
  
    // 根据边来建图
    for (int i = 1; i <= n; i++) {
        // 添加一条 x->y 的有向边
        cin >> x >> y;
        add_edge(x, y);
    }

    return 0;
}

带权图 - vector 存储

#include<bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;  // 最大顶点数量
typedef pair<int, int> PII;  // pair.first存放该边指向的结点号,pair.second存放该边的权重w
vector<PII> g[N]; // vector存储带权图

// 添加一条带权有向边:u -> v
void add_edge(int u, int v, int w) {
    g[u].push_back({v, w});
}

int main() {
    // 读取边的数量
    int n, x, y, w;
    cin >> n;
    // 建图
    for (int i = 1; i <= n; i++) {
        cin >> x >> y >> w;
        // 添加一条 x->y 的带权有向边
        add_edge(x, y, w);
    }

    return 0;
}

图的遍历

BFS

DFS


vector OI 案例 🧑🏻‍💻

OI 案例1

【题目描述】

实现一个线性表: 参照 sq_delete 函数,对一个 $n$ 不超过 $1024$ 的线性表进行删除操作。

【输入】

第一行有一个整数 $n$,表示线性表的大小,第二行有 $n$ 个整数,分别是 list1, list2 … listn 。
第三行有一个整数 $q$,表示 $q$ 次删除操作,接下来 $q$ 行,每行有一个整数 $k$,表示删除线性表中第 $k$ 个元素。
(输入有多组测试数据,以 EOF 结束)

【输出】

对于每次删除操作输出一行,如果 $k$ 不合法,输出 $-1$, 否则输出删除的元素。

【输入样例】
5 
3 2 1 5 4 
3 
5 
5 
2
【输出样例】
4 
-1 
2

【题目分析】

本题使用 STL 容器,可以很大程度上简化代码。

【C++ 代码】
#include<bits/stdc++.h>

using namespace std;
int n, q, tmp, id;
vector<int> v;
vector<int>::iterator it;

int main() {
    while (cin >> n) {
        v.clear();    //题目有多组样例,必须添加本行代码清空上一个v,否则会出错
        for (int i = 0; i < n; ++i) {
            cin >> tmp;
            v.push_back(tmp);
        }

        cin >> q;
        while (q--) {
            cin >> id;
            if (id < 1 || id > v.size()) {
                cout << -1 << endl;
            } else {
                it = v.begin();
                cout << *(it + id - 1)<<endl;   //vector 支持随机访问
                v.erase(it + id - 1);
            }
        }
    }
    return 0;
}

文章作者: Rickyの水果摊
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Rickyの水果摊 !
  目录