前些天做了好几道关于图的题,现在来个整理。
图的概念就不介绍了。
记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 }
正向的思路很复杂,但用逆向思维思考的话,代码就会非常简单。
然后第二个示例,是当要求图的存储进行排序的情况。
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 }