图论与图搜索

关于图论的知识很早就想给自己做一个整理,关于图的知识,应该是算法与数据结构里面最有意思的一部分了,也是我个人很喜欢的一块。之前一直觉得自己水平不够,写得不好。前几天参加数学建模的竞赛,拿到的题目的本质就是一道图搜索的题目。于是,比赛的时候恶补了一波,赛后又总结了一下。于是,把自己总结的贴在这里,做一个记录。

图的本质,描述的是一堆点与点的关系,这个点可以是道路结点,也可以是人,也可以是其他实体。

下面是我想写的:

  1. 递归
  2. 深度遍历和广度遍历
  3. 全排列和组合问题
  4. 八皇后问题
  5. A-star 算法

1. 递归和回溯

对于递归,如果这个问题,可以被调用自身并且在每一次调用的过程里面问题的规模还在不断的减少,那么这个递归的方法可以来解决这个问题。

举个典型的例子,二分查找,代码如下:

int binarySearch(int * arr ,int begin ,int end,int key){
    //递归的减枝条件
    //pass
    
    
    //递归结束条件
    if (begin >end  ){
        return -1
    }

    //找到解的情况
    if(key==arr[(end-begin)/2+begin]){
         return (end-begin)/2+begin;
    }

    //进入下一波递归
    if(key <arr[(end-begin)/2+begin] ){
         binarySearch(arr,begin,mid-1,key);
    }
    else{
        binarySearch(arr,mid+1,end,key);
    }
}

写一个递归的代码,我的理解是从四点入手,

  1. 递归结束的条件是什么
  2. 进入下一层递归的条件是什么
  3. 找到解的情况
  4. 为了减少搜索的规模,可以考虑减枝。减枝有两种,一种是合法性的减枝,一种是能够减少搜索规模的减枝

下面写一个其他的,组合问题。

LeetCode78:Subsets 
For example, 
If nums = [1,2,3], a solution is:
[ 
[3], 
[1], 
[2], 
[1,2,3], 
[1,3], 
[2,3], 
[1,2], 
[] 
]

思路:
对于一个元素,有两种选择,一种是把这个元素加入到当前的集合然后处理后面的元素,另一个是不把这个元素加入到当前结合然后处理后面的元素。

完全满足递归的思想:

  1. 可以调用自身
  2. 问题的规模在变小

so,代码如下:

#include <iostream>
#include <vector>
using namespace std;

void print_res(vector<vector<char>> &ans, vector<int> &path,vector<char> vc){
    //以print的方式输出
    for (int i=0;i<path.size();i++){
        if(path[i]==1){
            cout<<vc[i]<<"  ";
        }
    }
    cout<<endl;

    //将结果pushbach到ans里面
    vector<char> row;
    for (int i=0;i<path.size();i++){
        if(path[i]==1){
             row.push_back(vc[i]);
        }
    }
    ans.push_back(row);
}

void dfs(vector<vector<char>> &ans ,vector<int> path,int index ,vector<char> &vc ){
    //减枝
    if (index >vc.size()){
        return ;  //剪枝 表示结束,需要return
    }
    //找到结果
    if(index==vc.size()){
        print_res(ans,path,vc);
        return;  //找到结果,也意味着这一层的搜索结束,然后return
    }
    //进入下一层的递归,进入递归之后,创建两个机器人干活,一个机器人取当前元素加入集合干活,另外一个机器人不取当前元素加入集合,然后干活
    //取  创建一个机器人,进入递归干活
    path[index]=1;
    dfs(ans,path,index+1,vc);
    // 对于进入递归之后,从递归出来,一定要记的清楚上一次递归的状态,这个非常非常的重要!!!! 
    path[index]=0;
    //不取 
    dfs(ans,path,index+1,vc);
}

vector<vector<char>>  subset(vector<char> & vc){
    vector<vector <char>> ans;
    vector<int> path(vc.size(),-1);
    int index=0;

    //进入递归
    //取当前元素,进入递归
    path[index]=1;
    dfs(ans,path,index+1,vc);

    //对于进入递归之后,从递归出来,一定要记的清楚上一次递归的状态,这个非常非常的重要!!!! 
    path[index]=0;
    //不取当前元素,进入递归
    dfs(ans,path,index+1,vc);
    return ans;
}

int main(){
    vector<char> vc;
    vc.push_back('a');
    vc.push_back('b');
    vc.push_back('c');
    vc.push_back('d');
    vector<vector <char>> ans=subset(vc);
    return 0;
}
image.png
深度优先遍历和广度优先遍历

深度优先遍历和广度优先遍历的算法本身并不是很难,很多书已经写的很好了。但是,深度优先的实现可以解决很多除了图遍历之外,还很适合解决很多搜索类的问题。而dfs的本质,也是一种递归。

看看八皇后问题

在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

这个问题,在搜索所有的状态空间,时间复杂度是O(N^N)。搜索过程,如下:

草图.png
#include <iostream>
#include <vector>
#include <set>
#include <stdlib.h>  

using namespace std;

//记录一下结果的个数
int times=0;

void print_res(vector<int> path ){
    times++;
    for (auto it =path.begin();it!=path.end();it++){
        cout<<*it<<"  ";
    }
    cout<<endl;
}

bool isHang(vector<int> path){
    set<int> path_set;

    for (auto it =path.begin();it!=path.end();it++){
        path_set.insert(*it);
    }

    if(path_set.size()==path.size()){
        return true;
    }
    else{
        return false;
    }
}

bool isXiexian(vector<int> path){
    for(int i=0;i<path.size()-1;i++){
        for(int j=i+1;j<path.size();j++){
            if(abs(path[i]-path[j])==abs(i-j) ){
                return false;
            }
        }
    }
    return true;
}

void dfs(int index,int n,vector<int> path){

    //找到结果 
    if(index==n){
        //判断结果的合法性

        if(isHang(path) && isXiexian(path)){
            print_res(path);
        }
        return ;
    }


    //进入下一层递归
    for(int i=0;i<n;i++){
        path[index]=i;
        dfs(index+1,n,path);
        path[index]=-1;
    }
}

void n_queen(int n){
    vector<int> path(n,-1);
    int index=0;
    for(int i=0;i<n;i++){
        path[index]=i;
        dfs(index+1,n,path);

        //清除上一次进入递归的状态
        path[index]=-1;
    }
}

int main(){
    const int n=8;
    n_queen(n);
    cout<<endl;
    cout<<"times : "<<times<<endl;
    return 0;
}
A-star 算法

to-do

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,083评论 0 12
  • 数据结构与算法--图的搜索(深度优先和广度优先) 有时候我们需要系统地检查每一个顶点或者每一条边来获取图的各种性质...
    sunhaiyu阅读 2,611评论 0 5
  • 也许繁华和荒芜之间的区别 只在一念之间 也许你想要的现在和未来 遥远的就在眼前 你还不懂得世事艰难 是怎样的艰难 ...
    miss晴安阅读 223评论 0 2
  • 《远处》 我站在远处 在风雨江山之外我看着 眼前你的身影轻轻 如河畔细柳一般 悠悠的荡着秋千 落叶相逐 你没有停留...
    瓦尔登野人阅读 122评论 0 0
  • 一早醒来,微信上有一个加好友请求,对方自称是某某教练学院的,来自某个群聊。我想了想,通过了好友验证。 我简单浏览了...
    培训师张岚阅读 508评论 6 2