poj1236 强连通分支+缩点

来源:互联网 发布:亮度自动调节软件 编辑:程序博客网 时间:2024/06/11 04:20

/******************************************************************** ** @file    poj1236.cpp ** @date    Wed Apr 27 19:59:56 2011 ** @brief   *******强连通分支+缩点********** **      ********************************************************************/#include<iostream>#include<cstring>#include<stack>#include<vector>using namespace std;#define MAX 103vector<int>v[MAX];int n,length=0;stack<int>s;int DFN[MAX];//定义DFN(u)为节点u搜索的次序编号(时间戳),int low[MAX];/*Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号 */bool inStack[MAX];int belong[MAX];/*belong[i]表示第i个节点输入belong[i]分支 */int number=0;bool in[MAX];//标记一个连通分支的入度是否为0bool out[MAX];//标记一个连通分支出度是否为0void init(){  cin>>n;int j,num;  for(int i=0;i<n;++i){    while(cin>>num){      if(num==0)break;      v[i].push_back(num-1);//第i个顶点与num-1这个顶点相连    }  }}void Tarjan(int u){//u是从0开始,也就是顶点是0,1,2,3,.......  DFN[u]=low[u]=length++;  inStack[u]=true;  s.push(u);int j;  for(int i=0;i<v[u].size();++i){   j=v[u][i];//找到与顶点u相连的j    if(DFN[j]==-1){      Tarjan(j);      low[u]=min(low[u],low[j]);    }    else if (inStack[j]){      low[u]=min(low[u],DFN[j]);    }  }  if(low[u]==DFN[u]){    number++;//分支个数    do{       j=s.top();s.pop();       belong[j]=number;//标记各个点属于哪个分支1,2,3,.........      inStack[j]=false;    }while(j!=u);  }}void solve(){  memset(DFN,-1,sizeof(DFN));  memset(low,-1,sizeof(low));  memset(inStack,0,sizeof(inStack));  for(int i=0;i<n;++i)    if(DFN[i]==-1)      Tarjan(i);}int main(int argc, char *argv[]){  init();  solve();  memset(out,true,sizeof(out));  memset(in,true,sizeof(in));  for(int i=0;i<n;++i){    for(int j=0;j<v[i].size();++j){      int d=v[i][j];      int u=belong[i];int vv=belong[d];      if(u!=vv) {//次两点属于两个不同的连通分支,相应的入度,出度不为0        out[u]=false;//标记相应的出度不为0        in[vv]=false;      }    }        }  int num_in=0,num_out=0;  for(int i=1;i<=number;++i){    if(out[i]==true)num_out++;    if(in[i]==true)num_in++;  }  cout<<num_in<<endl<<(number==1?0:max(num_in,num_out))<<endl;  return 0;}


原创粉丝点击