poj-1236(强连通分量)
题意:给你n个点,每个点可能有指向其他点的单向边,代表这个点可以把软件传给他指向的点,然后解决两个问题,
1、问你最少需要给几个点,才能使所有点都能拿到软件;
2、问你还需要增加几条单向边,才能使任意两点可达;
解题思路:
如果一个点没有被其他点指向,也就是入度为0,那么这个点在一开始肯定要给,因为有环的话,环内的点一定可达,所以先缩点,问题1的答案就是入度为0的强连通分量的个数;
问题2的答案就是所有强连通分量的max(入度为0,出度为0);
#include<iostream> #include<algorithm> #include<queue> #include<vector> #include<cstring> #include<stack> #include<cstdio> #define maxn 100005 using namespace std; struct Edge { int next; int to; }edge[maxn]; struct node { int x; int y; }a[maxn]; int sccno[maxn]; int visit[maxn]; int head[maxn]; int low[maxn]; int dfn[maxn]; int indeg[maxn]; int outdeg[maxn]; int instack[maxn]; int cnt; int step; int index; int scc_cnt; int cot; vector<int>scc[maxn]; void add(int u,int v) { edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } void tarjan(int x) { low[x]=dfn[x]=++step; instack[++index]=x; visit[x]=1; for(int i=head[x];i!=-1;i=edge[i].next) { if(!dfn[edge[i].to]) { tarjan(edge[i].to); low[x]=min(low[x],low[edge[i].to]); } else if(visit[edge[i].to]) { low[x]=min(low[x],dfn[edge[i].to]); } } if(low[x]==dfn[x]) { scc_cnt++; scc[scc_cnt].clear(); do { scc[scc_cnt].push_back(instack[index]); sccno[instack[index]]=scc_cnt; visit[instack[index]]=0; index--; }while(x!=instack[index+1]); } } void init() { scc_cnt=step=cnt=index=cot=0; memset(head,-1,sizeof(head)); memset(visit,0,sizeof(visit)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); } int main() { int n; int x; init(); scanf("%d",&n); for(int i=1;i<=n;i++) { while(scanf("%d",&x)) { if(x==0) break; a[++cot].x=i; a[cot].y=x; add(i,x); } } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=cot;i++) { if(sccno[a[i].x]!=sccno[a[i].y]) { indeg[sccno[a[i].y]]++; outdeg[sccno[a[i].x]]++; } } int ans1=0; int ans2=0; int in; for(int i=1;i<=scc_cnt;i++) if(indeg[i]==0) ans1++; printf("%d\n",ans1); if(scc_cnt==1) { printf("0\n"); } else { for(int i=1;i<=scc_cnt;i++) { if(outdeg[i]==0) ans2++; } in=max(ans1,ans2); printf("%d\n",in); } return 0; }