您的位置:首页 > 其它

22.5-5求有向图的分量图

2016-03-19 09:45 295 查看
22.5-5求有向图的分量图

1.求出强连通分量

(1)第1次dfs,求出(逆)拓扑序

(2)第2次对以逆图的逆拓扑序dfs,得到的DFS森林,便求出强连通分量。期间要记录结点v所属的强连通分量为scc_count。

2.对于原图的每条边,若两个端点不属同一强连通分量,即!stronglyreachable(v,t),便加进DAG中

参考资料:C++算法--图算法(第3版)

P14-15 IO

P23-24 SparseMutiGRAPH

P28 InDegree

P173 StronglyConnected
P180 SccDAG

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
struct Edge{
int v,w;
Edge(int v=-1,int w=-1):v(v),w(w){}
};
class SparseMutiGRAPH{//邻接链表表示的稀疏图
int Vcount,Ecount;//点数,边数
bool digraph;//true为有向图,false为无向图
struct node{
int v;node*next;
node(int v,node*next):v(v),next(next){}
};
typedef node* link;
vector<link> adjacency;//邻接链表
public:
SparseMutiGRAPH(int Vcount,bool digraph=false):adjacency(Vcount),Vcount(Vcount),Ecount(0),digraph(digraph){
adjacency.assign(Vcount,(node*)NULL);//adjacency大小置为Vcount,每个元素为NULL
}
int V() const{return Vcount;}
int E() const{return Ecount;}
bool directed() const{return digraph;}
void insert(Edge e)
{
int v=e.v,w=e.w;
//将w插入到v的邻接链表表头
adjacency[v]=new node(w,adjacency[v]);
if(!digraph) adjacency[w]=new node(v,adjacency[w]);
Ecount++;
}
void traverse(void func(int v,int w)){
for(int v=0;v<Vcount;v++){
for(link t=adjacency[v];t;t=t->next)
func(v,t->v);
}
}
~SparseMutiGRAPH(){
for(vector<link>::iterator it=adjacency.begin();it!=adjacency.end();it++){
link node=*it,node_del=NULL;
while(node){
node_del=node;node=node->next;
delete node_del;
}
}
}
class adjacencyIterator;
friend class adjacencyIterator;
};

class SparseMutiGRAPH::adjacencyIterator{
const SparseMutiGRAPH &G;
int v;link t;
//调用begin()后,再调用一系列的next()(每次调用前要判断是否end())
//得到G中v的邻接顶点序列
public:
adjacencyIterator(const SparseMutiGRAPH &G,int v):G(G),v(v),t(NULL){}
int begin(){t=G.adjacency[v];return t?t->v:-1;}
int next(){
if(t) t=t->next;
return t?t->v:-1;
}
bool end(){return t==NULL;}
};
template<class inGRAPH,class outGRAPH>
void inverse(const inGRAPH & G,outGRAPH & R)
{//求G的逆图R
for(int v=0;v<G.V();v++){
typename inGRAPH::adjacencyIterator A(G,v);
for(int w=A.begin();!A.end();w=A.next())
R.insert(Edge(w,v));
}
}
template<class GRAPH>
class IO{//输入的结点编号是1~G.V(),但实际存放的是0~G.V()-1
public:
static void show(const GRAPH& G){
for(int v=0;v<G.V();v++){
cout.width(2);cout<<v+1<<":";
typename GRAPH::adjacencyIterator A(G,v);
for(int t=A.begin();!A.end();t=A.next()){
cout.width(2);cout<<t+1;
}
cout<<endl;
}
}/*
static void scan(GRAPH& G)
{
int Ecount;cin>>Ecount;
for(int i=0;i<Ecount;i++){
int v,w;cin>>v>>w;
G.insert(Edge(v,w));
}
}*/
static void scan(GRAPH &G){//第i行代表第i行指向的结点,空格隔开,以0结束
for(int v=0;v<G.V();v++){
int node;
while(cin>>node&&node) G.insert(Edge(v,node-1));
}
}
};
template<class GRAPH>
class StronglyConnected{
const GRAPH &G;
struct Vertex{bool visit;int scc;/*所属的scc的编号*/};
vector<Vertex> vertex;
int scc_count;vector<int>topo_list;

void dfs1(const GRAPH& G,int v)
{//第1次dfs,求出(逆)拓扑序
vertex[v].visit=true;//cout<<"visit:"<<v<<endl;
typename GRAPH::adjacencyIterator A(G,v);
for(int t=A.begin();!A.end();t=A.next())
if(!vertex[t].visit) dfs1(G,t);
topo_list.push_back(v);//逆拓扑序
//cout<<"push:"<<v;
}
void clearVisit(){
for(int v=0;v<G.V();v++) vertex[v].visit=false;
}
void dfs2(const GRAPH& G,int v)
{//第2次对以逆图的逆拓扑序dfs,求出强连通分量
//点v所属的强连通分量为scc_count
vertex[v].scc=scc_count;
vertex[v].visit=true;
typename GRAPH::adjacencyIterator A(G,v);
for(int t=A.begin();!A.end();t=A.next())
if(!vertex[t].visit) dfs2(G,t);
}

public:
StronglyConnected(const GRAPH &G):G(G),vertex(G.V()),scc_count(0){
clearVisit();
//for(int i=0;i<G.V();i++) cout<<vertex[i].visit;
for(int v=0;v<G.V();v++)
if(!vertex[v].visit) dfs1(G,v);
GRAPH R(G.V(),G.directed());
inverse(G,R);
clearVisit();
for(vector<int>::reverse_iterator it=topo_list.rbegin();it!=topo_list.rend();it++)
if(!vertex[*it].visit){
dfs2(R,*it);scc_count++;
}
}
bool stronglyreachable(int v,int w) const
{return vertex[v].scc==vertex[w].scc;}
int count() const {return scc_count;}
int operator[](int v)const{return vertex[v].scc;}
int SCC(int v)const{return vertex[v].scc;}
};
template<class GRAPH>
class SccDAG{
const GRAPH &G;
const StronglyConnected<GRAPH>& GSC;
public:
GRAPH* DAG;
SccDAG(const GRAPH& G):G(G),GSC(StronglyConnected<GRAPH>(G)){
//GSC=new StronglyConnected<GRAPH>(G);
DAG=new GRAPH(GSC.count(),true);
cout<<"所属分量:"<<endl;
for(int v=0;v<G.V();v++) cout<<GSC[v]<<" ";cout<<endl;
for(int v=0;v<G.V();v++){
typename GRAPH::adjacencyIterator A(G,v);
for(int t=A.begin();!A.end();t=A.next())
if(!GSC.stronglyreachable(v,t))
DAG->insert(Edge(GSC[v],GSC[t]));
}
}
~SccDAG(){delete DAG;}
};
template<class GRAPH>
class InDegree{
const GRAPH& G;
vector<int>degree;
public:
InDegree(const GRAPH&G):G(G),degree(G.V(),0){
for(int v=0;v<G.V();v++){
typename GRAPH::adjacencyIterator A(G,v);
for(int t=A.begin();!A.end();t=A.next()) degree[t]++;
}
}
int operator[](int v)const{return degree[v];}
};
/*
13
3 0
1 0
5 4 0
3 5 0
7 6 0
4 1 0
1 8 0
9 0
8 0
7 9 13 0
10 0
5 10 0
11 12 0*/
int main()
{
freopen("8.txt","r",stdin);
int Vcount;cin>>Vcount;
typedef SparseMutiGRAPH GRAPH;
GRAPH G(Vcount,true);
IO<GRAPH>::scan(G);
cout<<"原图:"<<endl;
IO<GRAPH>::show(G);
GRAPH R(G.V(),G.directed());
inverse(G,R);
cout<<endl;
cout<<"逆图:"<<endl;
IO<GRAPH>::show(R);
cout<<endl;
SccDAG<GRAPH> DAG(G);
cout<<"分量图:"<<endl;
IO<GRAPH>::show(*DAG.DAG);
InDegree<GRAPH> degree(G);
cout<<endl;cout<<"G的入度:"<<endl;
for(int v=0;v<G.V();v++) cout<<degree[v]<<" ";
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息