USACO5.3 校园网Network of Schools(Tarjan缩点)

满分做法:

子任务A的答案应为缩点之后,入度为\(0\)的个数。子任务B的答案为入度和出度为\(0\)个数的最大值。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxm=2e4+7;
int pre[maxm],last[maxm],dfn[maxm],low[maxm],other[maxm],l;
bool vis[maxm];
int sta[maxm],top=0,tot=0,size[maxm],id[maxm];
int n,from[maxm],ru[maxm],ans,chu[maxm],ans1,idd;
void add(int x,int y)
{
 l++;
 from[l]=x;
 pre[l]=last[x];
 last[x]=l;
 other[l]=y;
}
void dfs(int x)
{
  dfn[x]=low[x]=++tot;
  vis[x]=1;
  sta[++top]=x;
  for(int p=last[x];p;p=pre[p])
  {
   int v=other[p];
   if(!dfn[v])
   {
   	dfs(v);
   	low[x]=min(low[x],low[v]);
   }
   else if(vis[v]) low[x]=min(low[x],dfn[v]);
  }
  if(dfn[x]==low[x])
  {
    int y=0;
    idd++;
	while(y!=x)
	{
	  y=sta[top--];
	  vis[y]=0;
	  size[x]++;
	  id[y]=x;
	}
  }
}
int main()
{ 
 scanf("%d",&n);
 for(int i=1;i<=n;i++)
 {
   int x;
   while(scanf("%d",&x))
   {
   	if(x==0) break;
   	add(i,x);
   }
 }
 for(int i=1;i<=n;i++)
 {
  if(!dfn[i])
  dfs(i);	
 }
 for(int i=1;i<=l;i++)
 {
  int x=id[from[i]],y=id[other[i]];
  if(x!=y)
  {
    ru[y]++;
    chu[x]++;
  }
 }
// cout<<id[1]<<" "<<id[2]<<" "<<id[5]<<endl;
 for(int i=1;i<=n;i++)
 { 
  if(!ru[i]&&low[i]==dfn[i])
  ans++;
  if(!chu[i]&&low[i]==dfn[i])
  ans1++;
 } 
 if(idd==1)
 printf("1\n0\n");
 else 
 printf("%d\n%d\n",ans,max(ans,ans1));
 return 0; 
} 
posted @ 2019-11-11 16:16  lihan123  阅读(114)  评论(0编辑  收藏  举报