您的位置:首页 > 运维架构

poj 2186 Popular Cows (tarjan + 缩点)

2012-08-25 16:29 423 查看
题意 :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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: