http://acm.timus.ru/problem.aspx?space=1&num=1742

连通分量 

方法: 找到环 缩点  建立新图 新图是一个森林

新建的的森林 有多少节点 那么就有最多多少team   有多少叶子节点 那么最少就有多少team

注意由于n比较太 如果原图有一条很长的直线的话 会爆栈  所以自己开了一个栈  这种错误多次遇到 以后要注意呀

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>

#define LL long long
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
const int INF=0x3f3f3f3f;
const int N=100005;
vector<int>str[N];
vector<int>newtree[N];
int dfn[N],low[N],f[N],deep;
bool in[N],visited[N];
int minnum,maxnum;
int st[N],I;
void buildtree(int x)
{//cout<<x<<endl;
    for(unsigned int i=0;i<str[x].size();++i)
    {
        if(f[x]!=f[str[x][i]])
        {newtree[f[x]].push_back(f[str[x][i]]);}
    }
}
void Tarjan(int x)
{
    low[x]=dfn[x]=deep++;
    in[x]=true;
    visited[x]=true;
    st[I++]=x;
    for(unsigned int i=0;i<str[x].size();++i)
    {
        if(!visited[str[x][i]])
        {
            Tarjan(str[x][i]);
            low[x]=min(low[x],low[str[x][i]]);
        }else if(in[str[x][i]]==true)
        {
            low[x]=min(low[x],dfn[str[x][i]]);
        }
    }
    if(dfn[x]==low[x])
    {
        int k=I;
        while(st[k-1]!=x)
        {
            f[st[k-1]]=x;
            in[st[k-1]]=false;
            --k;
        }
        f[x]=x;
        in[x]=false;
        while(st[--I]!=x)
        buildtree(st[I]);
        buildtree(st[I]);
    }
}
void dfs(int x)
{
    ++maxnum;
    visited[x]=true;
    if(newtree[x].size()==0)
    {++minnum;return ;}
    for(unsigned int i=0;i<newtree[x].size();++i)
    {
        if(!visited[newtree[x][i]])
        dfs(newtree[x][i]);
    }
}
int main()
{
    //freopen("data.txt","r",stdin);
    int n;
    while(cin>>n)
    {
       for(int i=1;i<=n;++i)
       {str[i].clear();newtree[i].clear();}
       for(int i=1;i<=n;++i)
       {
           int pre;
           cin>>pre;
           str[pre].push_back(i);
           //cout<<f<<" "<<i<<endl;
       }
       memset(visited,false,sizeof(visited));
       deep=0;
       I=0;
       for(int i=1;i<=n;++i)
       if(visited[i]==false)
       Tarjan(i);
       minnum=0;
       maxnum=0;
       memset(visited,false,sizeof(visited));
       for(int i=1;i<=n;++i)
       {
           if(!visited[i]&&f[i]==i)
           dfs(i);
       }
       cout<<minnum<<" "<<maxnum<<endl;
    }
    return 0;
}

 

posted on 2012-10-22 21:42  夜->  阅读(276)  评论(0编辑  收藏  举报