使用Tarjan进行缩点,得到一个SCC图、
这个图有多少个入度为0的,多少个出度为0的。
假设有n个入度为0,m个出度为0
那么需要给n个点才能传遍所有点,需要加max(n,m)条边才能使整个图变成强连通分量
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<string>
//#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
struct Node{
int to,next;
}edge1[maxn*100],edge2[maxn*100];
int head1[maxn],head2[maxn];
int mark1[maxn],mark2[maxn];
int tot1,tot2;
int num,setNum[maxn];
int cnt1,cnt2,st[maxn],belong[maxn];
struct Edge{
int l,r;
}e[maxn*100];
void add(int a,int b)
{
edge1[tot1].to=b;edge1[tot1].next=head1[a];head1[a]=tot1++;
edge2[tot2].to=a;edge2[tot2].next=head2[b];head2[b]=tot2++;
}
void DFS1(int x)
{
mark1[x]=1;
for(int i=head1[x];i!=-1;i=edge1[i].next)
if(!mark1[edge1[i].to])DFS1(edge1[i].to);
st[cnt1++]=x;
}
void DFS2(int x)
{
mark2[x]=1;
num++;
belong[x]=cnt2;
for(int i=head2[x];i!=-1;i=edge2[i].next)
if(!mark2[edge2[i].to])DFS2(edge2[i].to);
}
int main()
{
int n,m;
while(scanf("%d",&n)!=EOF)
{
int w,v;
tot1=tot2=1;
for(int i=1;i<=n;i++)
{
head1[i]=head2[i]=-1;
mark1[i]=mark2[i]=0;
}
m=0;
for(w=1;w<=n;w++)
{
while(scanf("%d",&v)&&v){
m++;e[m].l=w,e[m].r=v;
add(w,v);
}
}
cnt1=cnt2=1;
for(int i=1;i<=n;i++){
if(!mark1[i])DFS1(i);
}
for(int i=cnt1-1;i>=1;i--)
{
if(!mark2[st[i]])
{
num=0;
DFS2(st[i]);
setNum[cnt2++]=num;
}
}
int out[maxn],in[maxn];//计算出度和入度
memset(out,0,sizeof(out));
memset(in,0,sizeof(in));
for(int i=1;i<=m;i++)
{
if(belong[e[i].l]!=belong[e[i].r])
{
out[belong[e[i].l]]++;
in[belong[e[i].r]]++;
}
}
int res1=0;//出度为0的个数
int res2=0;//入度为0的个数
for(int i=1;i<cnt2;i++)
{
if(!out[i]) res1++;
if(!in[i]) res2++;
}
//下面这个是关键,整张图就一个连通分量时,输出0,1.WR了好几次呢
if(cnt2==2) {printf("1\n0\n");continue;}
printf("%d\n",res2);
printf("%d\n",res1>res2?res1:res2);
}
return 0;
}
第二种Tarjan求解!!
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define N 105
vector<int> e[N];
int dfn[N], low[N],stap[N], stop,belong[N],outdeg[N],indeg[N],dindex, cnt;
bool instack[N];
int n, m;
void tarjan(int x){
int y = 0;
dfn[x]=low[x]=++dindex;
instack[x]=true;
stap[++stop]=x;
for (int i=0; i<e[x].size(); i++) {
y=e[x][i];
if (!dfn[y]) {
tarjan(y);
if (low[y]<low[x]) {
low[x]=low[y];
}
}
else if (instack[y]&&dfn[y]<low[x]){
low[x]=dfn[y];
}
}
if (dfn[x]==low[x]) {
cnt++;
while (y!=x) {
y=stap[stop--];
instack[y]=false;
belong[y]=cnt;
}
}
}
void solve(){
stop=dindex=cnt=0;
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
memset(outdeg, 0, sizeof(outdeg));
memset(indeg, 0, sizeof(indeg));
for (int i=1; i<=n; i++) {
if (!dfn[i]) {
tarjan(i);
}
}
}
int main(){
int temp;
while (~scanf("%d", &n)) {
for (int i=1; i<=n; ++i) {
e[i].clear();
}
for (int i=1; i<=n; i++) {
while (scanf("%d",&temp)) {
if (temp==0) {
break;
}
e[i].push_back(temp);
}
}
solve();
for (int i=1; i<=n; i++) {
int size=e[i].size();
for (int j=0; j<size; j++) {
if (belong[i]!=belong[e[i][j]]) {
outdeg[belong[i]]++;
indeg[belong[e[i][j]]]++;
}
}
}
int sumout=0,sumin=0;
for (int i=1; i<=cnt; i++) {
if (outdeg[i]==0) {
sumout++;
}
if (indeg[i]==0) {
sumin++;
}
}
if (cnt==1) {
printf("1\n0\n");
}
else
printf("%d\n%d\n",sumin,max(sumin,sumout));
}
return 0;
}