题意 :n头奶牛,m组关系(a b代表a认为b受欢迎)。求最后有多少头奶牛所有奶牛都认为它受欢迎。
思路:首先用tarjan算出连通分支数,将所有点都标上所属连通分支color。将每个分支看做一个点,若某点a受到另一点b联系,则说明该点a代表的连通分支中每个原始点都受到b中以及所有认为b受欢迎的点的欢迎,所以此处用dfs计算出每个分支中被多少人欢迎。
代码(比较繁琐):
#include<iostream>
#include<string.h>
#define size 10010
using namespace std;
struct E
{
int v, next;
}e[size*5],e1[size*5];
int head[size],in[size],stack[size] ,head1[size];
int dfn[size], low[size];
int num[size] ,rd[size], lian[size];
int top ,top1 , s ,color , step ,sum;
int n,m;
void init()
{
for(int i=0;i<size;i++)
{
head[i]=head1[i]=-1;
in[i]=stack[i]=dfn[i]=low[i]=num[i]=lian[i]=0;
}
step=top=top1=color=0; s=-1;
}
void insert(int u , int v)
{
e[top].v=v; e[top].next=head[u]; head[u]=top++;
}
void insert1(int u , int v)
{
e1[top1].v=v; e1[top1].next=head1[u]; head1[u]=top1++;
}
void tarjan(int u)
{
int v;
dfn[u]=low[u]=++step;
in[u]=1;
stack[++s]=u;
for(int i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v;
if(!dfn[v])
{
tarjan(v);
if(low[v]<low[u]) low[u]=low[v];
}
else if(in[v] && dfn[v]<low[u]) low[u]=dfn[v];
}
if(dfn[u]==low[u])
{
color++; int c=0; // cout<<endl<<"color "<<color<<" : "<<endl;
do
{
v=stack[s--];
in[v]=0;
lian[v]=color; //cout<<v<<" ";
c++;
}while(u!=v);
num[color]=c;
}
}
void dfs(int u)//连通分支u受到(xn-->...-->x1-->v-->u)所有v以及xi分支中所有原始点的欢迎。
{
for(int i=head1[u];i!=-1;i=e1[i].next)
{
int v=e1[i].v;
if( !low[ v])
{ // cout<<u<<"-------"<<v<<endl;
low[v]=1; dfs(v);
sum+=num[v];
}
}
}
int countRd()
{
int max=0 , t=0; //cout<<"color= "<<color<<endl;
for(int i=1;i<=n;i++)
{
for(int j=head[i]; j!=-1; j=e[j].next)
{
int v=e[j].v; // cout<<i<<"************"<<v<<endl;
if(lian[i]!=lian[v])
{
insert1(lian[v],lian[i]); //用e1记录每个连通分支间的关系。
}
}
}
for(int i=1;i<=color;i++)
{
rd[i]=0; //cout<<"rd["<<i<<"]=****= "<<rd[i]<<endl;
sum=rd[i]; for(int j=1;j<=color;j++) low[j]=0;
dfs(i);
rd[i]=sum+num[i] ; // cout<<"rd["<<i<<"]= "<<rd[i]<<endl;
}
for(int i=1;i<=color;i++)
{
if(rd[i]==n) t+=num[i];
}
return t;
}
int main()
{
int a, b;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
if(a!=b)
insert(a, b);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i); // cout<<"n= "<<n<<endl;
printf("%d\n",countRd());
}
return 0;
}
测试数据:
input
3 3
1 2
2 3
3 1
3 3
1 2
2 1
2 3
5 4
1 4
2 4
3 4
5 4
5 5
1 2
2 3
3 1
1 4
4 5
5 6
1 2
2 3
3 1
1 4
4 5
5 3
2 2
1 2
2 1
3 2
1 2
2 1
6 6
1 2
2 3
3 1
1 4
4 5
5 3
5 6
1 2
2 3
3 1
1 4
4 5
5 4
5 7
4 1
1 2
2 3
3 1
1 4
4 5
5 4
5 6
1 2
2 3
3 1
1 4
4 5
5 1
7 9
1 2
2 3
3 1
4 5
5 6
6 4
4 7
7 1
1 7
6 6
1 2
2 3
3 1
4 5
5 6
6 4
4 4
1 2
2 3
3 1
1 4
4 4
1 2
2 3
3 1
4 1
5 6
1 2
2 3
3 1
5 1
5 4
3 4
7 9
1 2
2 3
3 1
5 1
5 4
3 4
4 7
7 6
6 4
output
3
1
1
1
5
2
0
0
2
5
5
4
0
1
3
1
3