Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 18198 | Accepted: 7330 |
Description
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
Sample Input
3 3 1 2 2 1 2 3
Sample Output
1
题意:问那个牛最受欢迎。即问有多少个点其他任何点都能到达。单向连通。
思路:强连通缩点。求出度为零的点(强连通分量),这个点只能有一个,输出这个强连通分量重点的个数,否则输出0。
tarjian算法与gabow算法,二者的思想是相同的,只是一个用数组存,一个是用的栈来维护的那个追溯到的父节点。据说:Galow算法更省时。
tarjian算法代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
using namespace std;
#define max_n 10005
#define max_e 250002
#define inf 99999999
int stack[max_n],top;//栈
int isInStack[max_n];//是否在栈内
int low[max_n],dfn[max_n],tim;//点的low,dfn值;time从1开始
int node_id;//强连通分量的个数
int head[max_n],s_edge;//邻接表头 s_edge从1开始
int gro_id[max_n];//记录某个点属于哪个强连通分量
int n,m;
int in[max_n],out[max_n];//出度与入度
vector<int> vec[max_n];//边的后节点存储
struct Node
{
int to;
int next;
} edge[max_e];
void init()//初始化
{
s_edge=0;//存储
memset(head,0,sizeof(head));
memset(edge,0,sizeof(edge));
top=0;//tarjian初始化
tim=0;
node_id=0;
memset(isInStack,0,sizeof(isInStack));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(in,0,sizeof(in));//出度入度的初始化
memset(out,0,sizeof(out));
}
void addedge(int u,int v)
{
s_edge++;
edge[s_edge].to=v;
edge[s_edge].next=head[u];
head[u]=s_edge;
}
int min(int a,int b)
{
if(a<b)return a;
else return b;
}
void tarjan(int u)
{
//low值为u或u的子树能够追溯到得最早的栈中节点的次序号
stack[top++]=u;
isInStack[u]=1;
dfn[u]=++tim; //记录点u出现的记录,并放在栈中
low[u]=tim;
int e,v;
for(e=head[u]; e; e=edge[e].next) //如果是叶子节点,head[u]=0,edge[e].next=0;
{
v=edge[e].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(isInStack[v])
low[u]=min(low[u],dfn[v]);
}
int j;
if(dfn[u]==low[u])//找到一个强连通,元素出栈
{
node_id++;
while(j=stack[--top])
{
isInStack[j]=0;
gro_id[j]=node_id;
if(j==u)break;
}
}
}
void find()//tarjian寻找
{
for(int i = 1 ; i <=n ; ++i)
{
if(!dfn[i])
{
tarjan(i);
}
}
}
int main()
{
int a,b;
while(scanf("%d %d",&n,&m)!=EOF)
{
init();
for(int i=1; i<=n; i++)
vec[i].clear();
for(int i = 0 ; i <m ; ++i)
{
scanf("%d%d",&a,&b);
vec[a].push_back(b);
addedge(a,b);
}
find();
int sum=0,sum1=0;
for(int i=1; i<=n; i++)
{
for(int j=0; j<vec[i].size(); j++)//求强连通分量的出、入度
{
if(gro_id[i]!=gro_id[vec[i][j]])
{
out[gro_id[i]]++;
//in[gro_id[vec[i][j]]]++;
}
}
}
int ans=0;
for(int i=1; i<=node_id; i++)
{
if(out[i]==0)
{
sum++;
for(int j=1;j<=n;j++)
if(gro_id[j]==i)
sum1++;
}
if(ans<sum1)
ans=sum1;
//if(in[i]==0)
//sum1++;
}
if(sum==1)
cout<<ans<<endl;
else
cout<<"0"<<endl;
}
return 0;
}
/*
1
3 3
1 2
2 3
3 1
*/
Gabow算法代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<vector>
using namespace std;
#define max_n 10005
#define max_e 250002
#define inf 99999999
int stack[max_n],stack1[max_n],top,top1;//栈
int dfn[max_n],tim;//dfn值;time从1开始
int node_id;//强连通分量的个数
int gro_id[max_n];//记录某个点属于哪个强连通分量
int n,m;
int in[max_n],out[max_n];//出度与入度
vector<int> vec[max_n];//边的后节点存储
vector<int> cvec[max_n];//存储每个强连通分量的元素
void init()//初始化
{
top=0;//tarjian初始化
top1=0;
tim=0;
node_id=0;
memset(dfn,-1,sizeof(dfn));
memset(in,0,sizeof(in));//出度入度的初始化
memset(out,0,sizeof(out));
memset(stack,-1,sizeof(stack));
memset(stack1,-1,sizeof(stack1));
memset(gro_id,-1,sizeof(gro_id));
}
void Gabow(int u)
{
stack[++top]=u;
stack1[++top1]=u;//相当于low数组
dfn[u]=tim++; //记录点u出现的记录,并放在栈中
int e,v;
for(e=0; e<vec[u].size(); e++)
{
v=vec[u][e];
if(dfn[v]==-1)
{
Gabow(v);
}
else if(gro_id[v]==-1)
{
while(dfn[stack1[top1]]>dfn[v])
top1--;
}
}
int j;
if(stack1[top1]==u)//找到一个强连通,元素出栈
{
++node_id;
--top1;
do
{
gro_id[stack[top]]=node_id;
cvec[node_id].push_back(stack[top]);
}while(stack[top--]!=u);
}
}
void find()
{
for(int i = 1 ; i <=n ; ++i)
{
if(dfn[i-1]==-1)
{
Gabow(i-1);
}
}
}
int main()
{
int a,b;
while(scanf("%d %d",&n,&m)!=EOF)
{
init();
for(int i=0; i<=n; i++)
{
vec[i].clear();
cvec[i].clear();
}
for(int i = 0 ; i <m ; ++i)
{
scanf("%d%d",&a,&b);
vec[a-1].push_back(b-1);
}
find();
int sum=0,sum1=0;
for(int i=0; i<n; i++)
{
for(int j=0; j<vec[i].size(); j++)//求强连通分量的出、入度
{
if(gro_id[i]!=gro_id[vec[i][j]])
{
out[gro_id[i]]++;
//in[gro_id[vec[i][j]]]++;
}
}
}
int ans=0;
for(int i=1; i<=node_id; i++)
{
if(out[i]==0)
{
sum++;
ans=cvec[i].size();
}
}
if(sum==1)
cout<<ans<<endl;
else
cout<<"0"<<endl;
}
return 0;
}
/*
3 3
1 2
2 1
2 3
*/