图论 Graph theory

 

 关键词:DFS种子填充,BFS最短路树,拓补排序,欧拉回路,表达式树,有根树,最短路(Dijkstra / Bellman-ford / Floyd-Warshall),最小生成树(Kruskal),并查集

目录

一、用DFS求连通块(种子填充)

二、BFS最短路树

三、拓补排序

四、欧拉回路

五、树和图的转换

5.1 无根树转化为有根树

5.2 表达式树

六、最短路问题(Dijkstra / Bellman-ford / Floyd-Warshall)

6.1 Dijkstra算法

6.2 Bellman-Ford算法

6.3 Floyd算法

6.4 有向图的传递闭包

七、最小生成树(Kruskal)


和树不同,图(Graph)结构常用来存储逻辑关系为“多对多”的数据。

一、用DFS求连通块(种子填充)

典型例题 油田(Oil Deposits,Uva 572)说的是m行n列矩阵由字符“@”和“✳”组成,求@字符连通块。由于连通块元素之间是相互联系的,所以比较容易想到的方法就是使用递归遍历,也就是“图的DFS遍历”:

从每一个“@”格子出发,递归遍历周围的“@”格子,每次访问一个格子是就给它一个“连通分量编号”,避免访问多次。

 具体代码如下,首先定义头文件和全局数据类型:

#include <cstdio>
#include <cstring>
const int maxn=100+5;
//定义全局数据类型
char pic[maxn][maxn];     //存储整个矩阵
int m,n,idx[maxn][maxn];  //存储每个元素的“连通分量”编号id

接着就是核心代码——递归函数的定义,这里发现把本次递归暂停的条件设置在递归函数一开始要比设置在下一次递归前方便得多。参考以下代码,把越界处理和重复访问判断放在一开始比最后递归前判断是否进行本次递归要方便的多(简单来说就是不管周围情况咋样都去递归,进入了递归函数再判断自身是否合法),代码如下:

void dfs(int r,int c,int id)
{
    if(r<0||r>=m||c<0||c>=n)
        return;   //“出界”则暂停
    if(idx[r][c]>0||pic[r][c]!='@')
        return;   //不是@或已经访问并赋id的不需要继续遍历
    idx[r][c]=id; //联通分量编号
    //下面开始递归八个周围元素
    for(int dr=-1;dr<=1;dr++){
        for(int dc=-1;dc<=1;dc++){
            if(dr!=0||dc!=0)    //同时为0就是本身,要避免
                dfs(r+dr,c+dc,id);
        }
    }
}

最后是main函数,主要思路就是遍历每一个元素都DFS一下:

int main(){
    while(scanf("%d%d",&m,&n)==2&&m&&n){  //确保输入行列数正确
        for(int i=0;i<m;i++)
            scanf("%s",pic[i]);     //一行行输入,比一个个元素代码简便
        memset(idx,0,sizeof(idx));  //id数组清零
        int cnt=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(idx[i][j]==0&&pic[i][j]=='@')
                    dfs(i,j,++cnt);
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}

上题的算法(求多维数组连通块)也称作“种子填充”(floodfill),可以用DFS(递归遍历)实现也可以用BFS(队列)实现,有兴趣可以查一下维基百科:

维基百科 种子填充http://en.wikipedia.org/wiki/Floodfillwf中有一道题关于 古代象形符号(Ancient Messages,World Finals 2011,Uva 1103),题目要求是识别6个象形文字,且这些图案可以拉伸:

 其实处理逻辑和上面的种子填充差不多,都是递归遍历找出黑色块,然后从黑色块组合中匹配对应的象形符号。由于“可拉伸”所以匹配时不是严格匹配,而是计数每一个黑色块组合中有多少个“空洞”(抓住性质——每一个象形符号的空洞数量不一致),就可以解决问题。

二、BFS最短路树

场景是有一个n行m列的网格迷宫,中间有数个障碍物,找寻找起点到终点的最短路径。可以联想到二叉树的BFS——也是从根节点距离从小到大的顺序遍历,所以这里也是使用相似的方法进行图的BFS遍历:

从起点开始遍历整个图,逐步计算出起点到每一个节点的最短记录(图a)

相同最短距离的放在一“层”,可以构造出指向起点的树(图b)

 通过BFS遍历可以构造出上述树——也叫最短路树(BFS树),可以画成如下的结构:

 (以上图片均参考《算法竞赛入门经典 第二版》)

经典例题 Abbott的复仇(Abbott's Revenge,ACM/ICPC World Finals 2000,Uva 816),讲的是一个最大为9*9个交叉点的迷宫,迷宫为方块型,只能沿着水平或竖直反向走。在迷宫的节点中移动时,有NEWS四个方向进入节点(北东西南),允许三个方式FLR出去(直行左转右转)。现在输入入口和出口,要求最短路。

本题中进入每个节点的三个性质特别重要——行位置、列位置和进入方向(NEWS)。所以可以定义每一个经过的节点为一个三元组(r,c,dir),由于dir为进入节点的方向,所以整条链的第一个节点不是(r0,c0,dir)而是(r1,c1,dir),是移动过一位后的节点作为链的首节点。出于节点的其他功能可以将三元组转化为结构体——这样可以形成一条完善的链表。

本题可以使用BFS最短路树的原因是,在迷宫中行走过程中,有些节点提供多个转向方向,多个分叉恰巧构成了二叉树的“分叉”,且节点之间相互联系,因此可以将图转化为树的BFS遍历。

首先由于4个进入方向和转向反向都是字母,可以转化为数字以便后期运算(反向数据化)。其中使用了strchr函数,格式为strchr(字符串,字符),返回值为字符在字符串中第一次出现的位置指针,所以如果要求下标时需要减去首地址(数组名)。代码如下: 

const char* dirs="NEWS";   //默认为顺时针旋转
const char* turn="FLR";    //转向反向
//将朝向转换为数字格式
int dir_id(char c){
    return strchr(dirs,c)-dirs;
}
//将转向转化为数字格式
int turn_id(char c){
    return strchr(turns,c)-turns;
}

接着是行走函数(移动函数),根据当前的状态和转弯方式,计算出后继状态。这里函数的返回值就是节点结构体(结构体较简单故未给出)。注意返回值是新结构体,而不是返回传入Node u的引用,因为原节点数据不能被改变,只能在函数中创建新节点并返回:

const int dr[]={-1,0,1,0};  //上下左右移动对应的元素行变化
const int dc[]={0,1,0,-1};  //上下左右移动对应的元素列变化
Node walk(const Node& u,int turn){
    int dir=u.dir;  //取出方向
    if(turn==1)     //左转(逆)
        dir=(dir+3)%4;      //逆时针转动一个方向
    if(turn==2)     //右转(顺)
        dir=(dir+1)%4;      //顺时针转动一个方向
    return Node(u.r+dr[dir],u.c+dc[dir],dir)
}

输入函数(略)作用是读取r0,c0,dir,并计算r1和c1,作为第一个节点。然后读入has_edge数组,这个数组的作用是储存每个节点从不同方向来的合法转动反向。

接着就是BFS的过程,依旧使用队列,并在遍历的同时计算该链的长度并储存本节点的父节点。其中使用两个数组:

d[r][c][dir] 储存起点到(r,c,dir)的最短路长度
p[r][c][dir] 储存本节点的父节点

BFS的主要代码如下:

void solve(){
    queue<Node> q;
    memset(d,-1,sizeof(d));
    Node u(r1,c1,dir);     //创建树的初始父节点(起点的后一个点)
    d[u.r][u.c][dir]=0;    //初始路径长度为0
    q.push(u);             //推入队列,开始遍历
    while(!q.empty()){
        Node u=q.front();  //存储队列最前的元素,并使其出队列
        q.pop();
        if(u.r==r2&&u.c==c2){
            //表示已经到达终点
            print_ans(u);
            return;
        }
        for(int i=0;i<3;i++){
            //对三个转向方向遍历,如果转向合理则进队列
            Node v=walk(u,i);
            if(has_edge[u.r][u.c][dir][i]&&inside(v.r,v.c)&&d[v.r][v.c][v.dir]<0){
                //即严格控制 可以转向+该节点存在(因为迷宫不是每个转角都存在)+没有被遍历过
                d[v.r][v.c][v.dir]=d[u.r][u.c][u.dir]+1;   //节点串长度
                p[v.r][v.c][v.dir]=u;          //储存父节点
                q.push(v);
            }
        }
    }
    printf("No Solution Possible\n");
}         

最后是输出函数,只需要从目的地节点开始反方向遍历即可,推荐使用不定长数

Graph Theory Authors: Adrian Bondy, U.S.R Murty Publisher: Springer; 3rd Corrected Printing edition (Aug 14 2008) ISBN-10: 1846289696 ISBN-13: 978-1846289699 = Product Description = The primary aim of this book is to present a coherent introduction to graph theory, suitable as a textbook for advanced undergraduate and beginning graduate students in mathematics and computer science. It provides a systematic treatment of the theory of graphs without sacrificing its intuitive and aesthetic appeal. Commonly used proof techniques are described and illustrated. The book also serves as an introduction to research in graph theory. = Table of Contents = Graphs - Subgraphs - Connected Graphs - Trees - Separable and Nonseparable Graphs - Tree-Search Algorithms - Flows in Networks - Complexity of Algorithms - Connectivity - Planar Graphs - The Four-Colour Problem - Stable Sets and Cliques - The Probabilistic Method - Vertex Colourings - Colourings of Maps - Matchings - Edge Colourings - Hamilton Cycles - Coverings and Packings in Directed Graphs - Electrical Networks - Integer Flows and Coverings - Unsolved Problems - References - Glossary - Index = Reviews = For more than three decades, the authors' Graph Theory with Applications (1976) has served as perhaps the classic introduction to graph theory. With happy shock, the reader learns that Bondy and Murty have updated the book, doubling its size. Three decades would count as a long time in the life of any active scientific pursuit, but the original year of publication saw the solution to the four-color conjecture that catalyzed a vast revitalization of graph theory. Graph theory, moreover, now has intimate interactions with computer science, practical and theoretical: three decades ago, computer networks barely existed and the founding papers of complexity theory had just appeared. Connections between graph theory and probability have also undergone a revolution. In short, the passage of time has transformed this subject in these and other ways, and the authors have transformed their book accordingly. They do, by choice, largely omit the theory of graph minors (developed by Paul Seymour and Neil Robertson and followers), which certainly now deserves a monographic treatment of its own. Summing up: Recommended. Lower-division undergraduate through professional collections. CHOICE This book is a follow-on to the authors' 1976 text, Graphs with Applications. What began as a revision has evolved into a modern, first-class, graduate-level textbook reflecting changes in the discipline over the past thirty years... This text hits the mark by appearing in Springer’s Graduate Texts in Mathematics series, as it is a very rigorous treatment, compactly presented, with an assumption of a very complete undergraduate preparation in all of the standard topics. While the book could ably serve as a reference for many of the most important topics in graph theory, it fulfills the promise of being an effective textbook. The plentiful exercises in each subsection are divided into two groups, with the second group deemed "more challenging". Any exercises necessary for a complete understanding of the text have also been marked as such. There is plenty here to keep a graduate student busy, and any student would learn much in tackling a selection of the exercises... Not only is the content of this book exceptional, so too is its production. The high quality of its manufacture, the crisp and detailed illustrations, and the uncluttered design complement the attention to the typography and layout. Even in simple black and white with line art, it is a beautiful book. SIAM Book Reviews "A text which is designed to be usable both for a basic graph theory course … but also to be usable as an introduction to research in graph theory, by including more advanced topics in each chapter. There are a large number of exercises in the book … . The text contains drawings of many standard interesting graphs, which are listed at the end." (David B. Penman, Zentralblatt MATH, Vol. 1134 (12), 2008) MathSciNet Reviews "The present volume is intended to serve as a text for "advanced undergraduate and beginning graduate students in mathematics and computer science" (p. viii). It is well suited for this purpose. The writing is fully accessible to the stated groups of students, and indeed is not merely readable but is engaging… Even a complete listing of the chapters does not fully convey the breadth of this book… For researchers in graph theory, this book offers features which parallel the first Bondy and Murty book: it provides well-chosen terminology and notation, a multitude of especially interesting graphs, and a substantial unsolved problems section…One-hundred unsolved problems are listed in Appendix A, a treasure trove of problems worthy of study… (In short) this rewrite of a classic in graph theory stands a good chance of becoming a classic itself." "The present volume is intended to serve as a text for ‘advanced undergraduate and beginning graduate students in mathematics and computer science’ … . The writing is fully accessible to the stated groups of students, and indeed is not merely readable but is engaging. The book has many exercise sets, each containing problems … ." (Arthur M. Hobbs, Mathematical Reviews, Issue 2009 C) "A couple of fantastic features: Proof techniques: I love these nutshelled essences highlighted in bordered frames. They look like pictures on the wall and grab the view of the reader. Exercises: Their style, depth and logic remind me of Lovász’ classical exercise book. Also the fact that the name of the author is bracketed after the exercise…Figures: Extremely precise and high-tech…The book contains very recent results and ideas. It is clearly an up-to-date collection of fundamental results of graph theory…All-in-all, it is a marvelous book." (János Barát, Acta Scientiarum Mathematicarum, Vol. 75, 2009)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhouqi_Hua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值