蕾姐讲过的例题..玩了两天后才想起来做 貌似省赛之后确实变得好懒了...再努力两天就可以去北京玩了!
顺便借这个题记录一下求强连通分量的算法
1 只需要一次dfs 依靠stack来实现的tarjan算法 每次走到一个点 马上把它压入栈中 每次对与这个点相连的点处理完毕 判断是否low[u]==dfn[u] 若是 开始退栈 直到栈顶元素等于u才退出(当栈顶元素等于u也需要pop) 每次一起退栈的点属于同一个强连通分量 储存图可以用链式前向星也可以用邻接矩阵更可以用vector 蕾姐说不会超时 我信了
2 需要两次dfs的kosara 在输入图的时候需要搞出来一个反向图以便第二次dfs使用 开始进行一次dfs 每当一个点要离开的时候就将其压入栈中 当所有的点都被遍历后 从栈顶元素开始进行反向搜索 一次搜到的点属于同一个强连通分量 其实..也需要用到栈...
需要注意的是 当使用tarjan时 dfs时如果判断dfn[v]时已经有了值 在else中需要有if条件(!id[v])
#include<stdio.h> #include<string.h> #include<algorithm> #include<map> #include<math.h> #include<iostream> #include<stack> #include<vector> using namespace std; int n,m; int id[10050]; int dfn[10050]; int low[10050]; int ans[10050]; int cd[10050]; int point[10050]; int num; int cnt; int tot; vector<int >q[10050]; stack<int >s; void init(){ for(int i=1;i<=n;i++) { id[i]=0; dfn[i]=0; low[i]=0; ans[i]=0; cd[i]=0; point[i]=-1; q[i].clear(); } num=cnt=tot=0; while(!s.empty()) s.pop(); } void dfs(int u){ dfn[u]=low[u]=++cnt; s.push(u); int v; int siz=q[u].size(); for(int i=0;i<siz;i++) { v=q[u][i]; if(!dfn[v]) { dfs(v); low[u]=min(low[u],low[v]); } else if(!id[v]) { low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]) { int temp=0; num++; while(!s.empty()) { int v=s.top(); s.pop(); temp++; id[v]=num; if(v==u) break; } ans[num]=temp; } } struct node { int v,nex; }; node a[10050]; void add(int u,int v) { a[tot].v=v; a[tot].nex=point[u]; point[u]=tot; tot++; } void jt(){ for(int i=1;i<=n;i++) { int siz=q[i].size(); for(int k=0;k<siz;k++) { int v=q[i][k]; if(id[v]!=id[i]) { cd[id[i]]++; } } } } void did(){ int can=0; int p=-1; for(int i=1;i<=num;i++) { if(cd[i]==0) { can++; p=i; } } if(can==1) { printf("%d\n",ans[p]); } else printf("0\n"); } int main(){ while(cin>>n>>m) { init(); for(int i=1;i<=m;i++) { int u,v; cin>>u>>v; q[u].push_back(v); } for(int i=1;i<=n;i++) { if(!dfn[i]) dfs(i); } jt(); did(); } }
时间: 2024-10-22 07:46:01