图论_图的基础(更新中)

图的定义:图G是一个有序二元组(V,E),其中V称为顶集(Vertices Set),E称为边集(Edges Set),E与V不相交。它们亦可写成V(G)和E(G)。 分类: 1.按边有无方向分为:无向图 和 有向图
图的存储与表示: 邻接矩阵:用一个二维数组g[n][n],进行村粗,g[i][j] = 1,表示有一条边<i,j>,从点i指向点j。 若为无向图 则g[i][j] = g[j][i] = 1 (矩阵一定关于对角线对称) 若为有向图 则g[i][j] = 1 复杂度O(n^2)  存储空间大小 n^2
邻接表:为每个顶点创建一个单链表,顶点u的单链表中存储和顶点u直接相连接的点的下标(去掉表中0,将原先的1直接改为对应下标) 存储空间大小 m 代码: const int N = 2e6 + 5; vector<int> g[N]; //u - v 无向 g[u].push_back(v); g[v].push_back(u); //u -> v 有向 g[u].push_back(v); //u -> v cost w 有权值图 typedef pair<int,int> pii; vector<pii> g[N]; g[u].pb(pii(v,w));
顶点的度、入度和出度 无向图:顶点v的度指和v相连的边的数量 a - b | \ | c - d degree(a) = 3,degree(b) = 2 有向图:顶点v的出度指以v为起点的边的数量,顶点v的入度指以v为终点的边的数量 _____v1 -> v2 |    /\  ___| \/    | \/   v5 ->  v3 -> v6 <- v4 |     /\    /\    | |     |_____|_____| |___________| degree_out(v1) = 2,degree_in(v1) = 1 degree_out(v3) = 2,degree_in(v3) = 3
拓扑排序 对于一个DAG(有向无环图)进行拓扑排序,是将所有的项点排成一个线性序列,使得对于图中任意一条有向边<u,v>,都满足u在v之前。(即优先点要满足入度为0) 注意点:拓扑排序不一定唯一(可能会同时产生多个入度为0的点) queue<int> q; if (in[i] = 0) q.push_back(i); for (...) {     in[g[q.top()]] -= 1; } //重复上述伪代码
拓扑排序例题:有N个比赛队(1 <= N < 500),编号依次为1,2,3...,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果 ,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。(hdu1285) 注意:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
Sample input 4 3 1 2 2 3 4 3 Sample output 1 2 4 3
//朴素方法 #include  <cstdio> #include <cstring> const int maxn = 505; int g[maxn][maxn];//路径 int in_degree[maxn];//入度 int ans[maxn]; int n,m,x,y; void toposort() {     for (int i = 1; i <= n; ++i)     {         for (int j = 1; j <= n; ++j)         {             if (g[i][j])             {                 ++in_degree[j];             }         }     }     for (int i = 1; i <= n; ++i)     {         //寻找编号最小且入度为0         int k = 1;         while (in_degree[k] != 0) ++k;         ans[i] = k;         in_degree[k] = -1;//更新为-1,不影响后续检测         for (int j = 1; j <= n; ++j)         {             if (g[k][j]) --in_degree[j];//相关入度减1         }     } } void init() {     memset(in_degree,0,sizeof(in_degree));     memset(ans,0,sizeof(ans));     memset(g,0,sizeof(g)); } int main() {     while(~scanf("%d%d",&n,&m))     {         init();         for (int i = 1; i <= m; ++i)         {             scanf("%d%d",&x,&y);             g[x][y] = 1;         }         toposort();         for (int i = 1; i < n; ++i)         {             printf("%d ",ans[i]);         }         printf("%d\n",ans[n]);     }     return 0; }
//拓扑排序 + 优先队列 #include <iostream> #include <queue> #include <cstdio> #include <cstring> using namespace std; const int maxn = 505; bool map[maxn][maxn]; int in[maxn]; priority_queue<int,vector<int>,greater<int> > q; void topo(int n) {     for (int i = 1; i <= n ; ++i)     {         if (in[i] == 0) q.push(i);     }     int c = 1;     while (!q.empty())     {         int v = q.top();         q.pop();         if (c != n)         {             cout << v << " ";             ++c;         }         else cout << v << endl;         for (int i = 1; i <= n; ++i)         {             if (!map[v][i]) continue;             --in[i];//保证已经push的不会重复push             if (!in[i]) q.push(i);         }     } } int main() {     int n,m,i,j;     while (cin >> n >> m)     {         memset(map,0,sizeof(map));         memset(in,0,sizeof(in));         while (m--)         {             cin >> i >> j;             if (map[i][j]) continue;             map[i][j] = 1;             ++in[j];         }         topo(n);     } }
//存疑 //邻接表 + 拓扑排序 (1)数组式邻接表: #include <iostream> using namespace std; const int maxn = 505; const int maxn1 = 250005; int ind[maxn];//入度 int adj[maxn1];//adjacency list邻接表位置值 int adj_next[maxn1];//邻接表下一指针 int tail[maxn];//邻接表尾 int main() {     int n,m,i,j,a,b;     while (scanf("%d%d",&n,&m) != EOF)     {         //初始化         for (i = 0; i <= n; ++i)         {             tail[i] = -1;             adj[j] = -1;             adj_next[i] = -1;             ind[i] = 0;         }         for (i = 0; i < m; ++i)         {             scanf("%d%d",&a,&b);             int x = tail[a],flag = 0;             while (x != -1)//判断是否重边             {                 if (adj[x] == b)                 {                     flag = 1;                     break;                 }                 x = adj_next[x];             }             if (!flag)//共联a的邻接表             {                 adj[i] = b;                 adj_next[i] = tail[a];                 tail[a] = i;                 ++ind[b];             }         }         for (i = 1; i <= n; ++i)//找n次         {             for (j = 1; j <= n; ++j)//遍历             {                 if (ind[j] == 0)//当入度为0,说明靠前                 {                     ind[j] = -1;//在下次寻找入度时为0跳过                     if (i == 1) printf("%d",j);                     else printf(" %d",j);                     //邻接位置入度减1                     for (int k = tail[j]; k != -1; k = adj_next[k])                     {                         --ind[adj[k]];                     }                     break;                 }             }         }         printf("\n");     }     return 0; }
上一篇:数据结构2021温习篇——图(7b)_邻接表


下一篇:LM2596S-ADJ 程控电压源