一天一道算法题——图

前些天做了好几道关于图的题,现在来个整理。

图的概念就不介绍了。

记u为起点,v为终点

最简单的存储方式:

vector<int> g[maxn];

在上面的vector里,如果正向建图,那么再输入的时候g[u].push_back(v);

如果反向建图,那么就是g[v].push_back(u);

以下是一个关于反向建图并dfs遍历的题目。

P3916 图的遍历

AC代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<stdio.h>
 4 #include<vector>
 5 #define maxn 100010
 6 using namespace std;
 7 
 8 int n, m, vis[maxn];
 9 vector<int> g[maxn];
10 
11 void dfs(int x,int d) {
12     if (vis[x])return;
13     vis[x] = d;
14     for (int i = 0; i < g[x].size(); i++) {
15         dfs(g[x][i], d);
16     }
17 }
18 
19 int main() {
20     cin >> n >> m;
21     int u, v;
22     for (int i = 1; i <= m; i++) {
23         scanf("%d%d", &u, &v);
24         g[v].push_back(u);//反向建图
25     }
26     for (int i = n; i >= 1; i--)dfs(i, i);
27     for (int i = 1; i <= n; i++)printf("%d ", vis[i]);
28     return 0;
29 }
View Code

正向的思路很复杂,但用逆向思维思考的话,代码就会非常简单。

然后第二个示例,是当要求图的存储进行排序的情况。

 1 struct edge {
 2     int u, v;//u起点,v终点
 3 }tmp;
 4 vector<int> e[100010];
 5 vector<edge> s;
 6 while (m--) {
 7     scanf("%d%d", &tmp.u, &tmp.v);
 8     s.push_back(tmp);
 9 }
10 sort(s.begin(), s.end(), cmp);
11 for (int i = 0; i < s.size(); i++) {
12     e[s[i].u].push_back(i);
13 }

情况稍微变的有点复杂,代码里的e同上个示例中的g,作用不变。但在排序(代码中假定是对每个相同的起点,按终点大小排列)的时候,需要建一个临时的vector s当存储。

相应的cmp

inline bool cmp(edge a, edge b) {
    if (a.v == b.v)return a.u < b.u;
    return a.v < b.v;
}

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

接下来是拓扑排序

拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。

由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。

(1) 选择一个入度为0的顶点并输出之;

(2) 从网中删除此顶点及所有出边。

循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列。

题目:P1113杂务

代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<stdio.h>
 4 #include<queue>
 5 using namespace std;
 6 const int N = 10010;
 7 queue<int> q;
 8 bool e[N][N];
 9 int n,ans,ti[N], mx[N], ru[N];
10 
11 void topo() {
12     for (int i = 1; i <= n; i++) {
13         if (ru[i] == 0) {//将入度为0的顶点放进q里
14             q.push(i);
15             mx[i] = ti[i];
16         }
17     }
18     while (!q.empty()) {
19         int d = q.front();//前序工作时间已经加上的顶点
20         q.pop();
21         for (int i = 1; i <= n; i++) {
22             if (e[d][i]) {
23                 ru[i]--;
24                 if (ru[i] == 0)q.push(i);
25                 mx[i] = max(mx[i], mx[d] + ti[i]);
26             }
27         }
28     }
29     for (int i = 1; i <= n; i++)
30         ans = max(ans, mx[i]);
31 }
32 
33 int main() {
34     cin >> n;
35     for (int i = 1; i <= n; i++) {
36         int a, b, c;
37         scanf("%d%d%d", &a, &b, &c);
38         ti[a] = b;
39         while (c != 0) {
40             ru[a]++;//入度
41             e[c][a] = true;//图的创立
42             scanf("%d", &c);
43         }
44     }
45     topo();//拓扑排序
46     printf("%d", ans);
47     return 0;
48 }
原文地址:https://www.cnblogs.com/zyyz1126/p/12695722.html