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