基本概念
顶点:表示某个事物或对象
边:表示事物与事物之间的关系
有向图:有向图中的边是有方向性的,无向图则没有方向
权重:即每条边都有与之对应的值
路径::一个顶点序列i1,i2........ik是图的一条路径,当且仅当边(i1,i2)(i2,i3).........(ik-1,ik)都在图中。如果除了第一个顶点和最后一个顶点之外,其余的顶点均不相同,那么这条路径称为简单路径
环:在路径的终点添加一条指向起点的边,就构成一条环路
连通图:设图G是无向图,当且仅当G的每一对顶点之间都有一条路径,则称G是连通图
强连通图:图G是一个有向图,当且仅当每一对不同的顶点u,v,从u到v和v到u都有一条有向路径
生成树:如果图H是图G的子图,且他们的顶点集合相同,并且H是没有环路的无向连通图(即一棵树),则称H是G的一棵生成树
二分图:图G的顶点被分为两个子集,而且每条边只能从一个子集到另一个子集
有向无环图
/*==================================================*\
| DAG的深度优先搜索标记
| INIT: edge[][]邻接矩阵; pre[], post[], tag全置0;
| CALL: dfstag(i, n); pre/post:开始/结束时间
\*==================================================*/
int edge[V][V], pre[V], post[V], tag;
void dfstag(int cur, int n)
{ // vertex: 0 ~ n-1
pre[cur] = ++tag;
for (int i=0; i<n; ++i) if (edge[cur][i]) {
if (0 == pre[i]) {
printf("Tree Edge!\n");
dfstag(i, n);
} else {
if (0 == post[i]) printf("Back Edge!\n");
else if (pre[i] > pre[cur]) printf("Down Edge!\n");
else printf("Cross Edge!\n");
}
}
post[cur] = ++tag;
}
拓扑排序
/*==================================================*\
| 拓扑排序
| INIT:edge[][]置为图的邻接矩阵;count[0…i…n-1]:顶点i的入度.
\*==================================================*/
void TopoOrder(int n){
int i, top = -1;
for( i=0; i < n; ++i ) {
if( count[i] == 0 ) { // 下标模拟堆栈
count[i] = top; top = i;
}
for( i=0; i < n; ++i ) {
if( top == -1 ) {
printf("存在回路\n");
return ;
} else {
int j = top; top = count[top];
printf("%d", j);
for( int k=0; k < n; ++k )
if( edge[j][k] && (--count[k]) == 0 ){
count[k] = top; top = k;
}
}
}
}
}
最短路径(Dijkstra)
/*==================================================*\
| Dijkstra数组实现 O(N^2)
| Dijkstra --- 数组实现(在此基础上可直接改为STL的Queue实现)
| lowcost[] --- beg到其他点的近距离
| path[] -- beg为根展开的树,记录父结点
\*==================================================*/
#define INF 0x03F3F3F3F
const int N;
int path[N], vis[N];
void Dijkstra(int cost[][N], int lowcost[N], int n, int beg) {
int i, j, min;
memset(vis, 0, sizeof(vis));
vis[beg] = 1;
for (i=0; i<n; i++) {
lowcost[i] = cost[beg][i];
path[i] = beg;
}
lowcost[beg] = 0;
path[beg] = -1; // 树根的标记
int pre = beg;
for (i=1; i<n; i++) {
min = INF;
for (j=0; j<n; j++)
// 下面的加法可能导致溢出,INF不能取太大
if (vis[j]==0 && lowcost[pre]+cost[pre][j]<lowcost[j]) {
lowcost[j] = lowcost[pre] + cost[pre][j];
path[j] = pre;
}
for (j=0; j<n; j++)
if (vis[j] == 0 && lowcost[j] < min){
min = lowcost[j];
pre = j;
}
vis[pre] = 1;
}
}
/*==================================================*\
| Dijkstra O(E * log E)
| INIT: 调用init(nv, ne)读入边并初始化;
| CALL: dijkstra(n, src); dist[i]为src到i的短距离
\*==================================================*/
#define typec int // type of cost const
typec inf = 0x3f3f3f3f; // max of cost
typec cost[E], dist[V];
int e, pnt[E], nxt[E], head[V], prev[V], vis[V];
struct qnode {
int v; typec c;
qnode (int vv = 0, typec cc = 0) : v(vv), c(cc) {}
bool operator < (const qnode& r) const { return c>r.c; }
};
void dijkstra(int n, const int src) {