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;}