DFS遍歷圖時的小技巧
阿新 • • 發佈:2018-12-07
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; }