DFS遍历图时的小技巧

Posted sqmax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DFS遍历图时的小技巧相关的知识,希望对你有一定的参考价值。

DFS遍历图时的小技巧

我们通常使用DFS遍历图时,用vis[i]=true;来标记访问过的节点,但是如果要让我们统计图中所有边的长度的话,如果我们还这样做的话,对于非环形图来说,没问题,但是对于环形图来说,就可能访问不到最后一条边,如A-B-C-A,A标记之后就不能统计到C-A了。
这时我们的办法是,每访问一条边后,就把它销毁,然后递归地去DFS时不再以vis[i]==false为条件去递归,而是直接以G[i][j]!=0为条件去递归。
这也是和平时DFS遍历图时有区别的地方,一个小技巧吧。

后来又看到别人的解法,先访问边,再判断vis[i],再去DFS,可见下面的DFS法二。

应用:1034 Head of a Gang (30 分)

//此题的难点在于DFS遍历每一个点后,都销毁走过的路径,不走回头路。 
//在递归时,不再以vis[i]==false问判断条件 ,因为vis[i]=true标记后,如果是环形图的话,那么最后一条边就不能访问到
//如A-B-C-A,刚开始时A被标记后,那么C-A这条边就不能在被访问到。 
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;

const int maxn=2010;//不能定义为1010时,会有段错误,必须定义为2000以上,由于通话记录有1000条,因此不同的人可能有2000个 
struct Gang{
    int head;
    int num;
};
int G[maxn][maxn];
int W[maxn];
bool vis[maxn];
int n,K;
vector<Gang> ans;
map<string,int> stringToInt;
map<int,string> intToString;
int numPerson;
int maxConnTime;
void DFS(int idx,int &total,int &num,int &head){
    if(vis[idx]==false){
        num++;
        vis[idx]=true;
    }
    if(W[idx]>maxConnTime){
        maxConnTime=W[idx];
        head=idx;           
    }
    for(int i=0;i<numPerson;i++){
        if(G[idx][i]){//这里不在以vis[i]==false为条件,因为对于环形图访问不到最后一条边 
            total+=G[idx][i];
//          num++;
            G[idx][i]=G[i][idx]=0;//访问后销毁边 
            DFS(i,total,num,head);
        }
    }
}
//法二 :先访问边,再DFS遍历 
/** 
void DFS(int idx,int &total,int &num,int &head){
    num++;
    vis[idx]=true;
    if(W[idx]>maxConnTime){
        maxConnTime=W[idx];
        head=idx;           
    }
    for(int i=0;i<numPerson;i++){
        if(G[idx][i]){
            total+=G[idx][i];
            G[idx][i]=G[i][idx]=0;
            if(vis[i]==false){
                DFS(i,total,num,head);  
            } 
        }
    }
}
*/ 
bool cmp(Gang a,Gang b){
    return intToString[a.head]<intToString[b.head];
}
int transfer(string name){
    if(stringToInt.find(name)==stringToInt.end()){
        stringToInt[name]=numPerson;
        intToString[numPerson]=name;
        return numPerson++;
    }else{
        return stringToInt[name];
    }
}
int main(){
    cin>>n>>K;
    for(int i=0;i<n;i++){
        string a,b;
        int w;
        cin>>a>>b>>w;
        int aId=transfer(a);
        int bId=transfer(b);
        G[aId][bId]+=w;
        G[bId][aId]=G[aId][bId];
        W[aId]+=w;
        W[bId]+=w;
    }
    for(int i=0;i<numPerson;i++){
        if(vis[i]==false){
            int total=0,num=0,head;
            maxConnTime=0;
            DFS(i,total,num,head);
            if(total>K&&num>2){
                Gang gang;
                gang.head=head,gang.num=num;
                ans.push_back(gang);
            }    
        }
    }
    sort(ans.begin(),ans.end(),cmp);
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++){
        cout<<intToString[ans[i].head]<<" "<<ans[i].num<<endl;
    }
    
    return 0;
}

以上是关于DFS遍历图时的小技巧的主要内容,如果未能解决你的问题,请参考以下文章

Android课程---Android Studio使用小技巧:提取方法代码片段

java.text.MessageFormat格式化字符串时的小技巧

DFS&BFS

019-dfs.bfs-图的遍历-《算法设计技巧与分析》M.H.A学习笔记

Java 集合(ListSet)遍历判断删除元素时的小陷阱

一点在绘制系统架构图时的思考