POJ 2186 Popular Cows【强连通Kosaraju+缩点】
2016-06-08 16:30
399 查看
Popular Cows
Description
Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is
transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
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
* Line 1: Two space-separated integers, N and M
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
Source
USACO 2003 Fall
题目大意:给你n头牛,m个关系,每个关系表示a崇拜b,问有多少牛被所有牛所崇拜。
思路:
根据样例可以看出,这个图不是DAG图,而是存在环的有向图,这里怎样处理留到之后来讨论,我们先讨论如何得出结论。
1、如果有这样一个DAG图:
(在DAG图中)我们不难分析,如果其点有出度,那么这个点首先一定就不是被所有牛崇拜的对象,所以如果一个点没有出度,那么这头牛就很有可能被所有牛所崇拜。根据这个图我们还能推出这样一个结论:如果出度为0的牛大于两个,那么就说明被所有牛都崇拜的个数为0,因为这里有两头及以上牛互相没有崇拜关系。
那么如果图变成了这样:
这个时候4就是被所有牛崇拜的对象。
综上所述,在DAG图中,出度为0的节点如果只有一个,那么这个节点就一定是被所有牛崇拜的对象,如果出度为0的节点为0或者是出度为0的节点个数大于等于2,那么就没有牛满足被所有牛崇拜的条件,也就是被所有牛崇拜的牛的个数为0.
2、处理有向环。
这个时候我们做题的目标性就很明确了,如何将一个带有向环的图变成一个DAG图,如果大家有对最小树型图之类的需要缩点的算法有所了解的话,相信大家已经明确了答案,对于一个环,我们可以当做一个点来处理。对于一个有向环,他们其中每两个节点又是强连通的,而且强连通算法又是辣么的快速 ,所以我们这里就使用强连通算法来确定强连通分量(有向环),并在处理过程中,将一个环染色,也就是将一堆点变成了一个点,这样,我们就得到了DAG图。
既然我们这样处理就得到了DAG图,那么AC也就近在眼前了。
3、代码实现
我这里求强连通分量的算法使用的是Kosaraju,两次Dfs,过程中染色,对于每个缩点,不用计较其出边的个数,要不然我们在这里要处理更多麻烦的步骤,我们要统计的是出度为0的点的个数,出度为1,还是出度为20,我们都不关心,所以在这里缩点之后边的缩减我这里就不进行处理了。
AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
int head[100000];
int head2[100000];
struct EdgeNode
{
int from;
int to;
int next;
}e[100000],ee[100000];
int n,m,cont,cont2,sig;
int degree[1000000];
int vis[1000000];
int num[1000000];
int color[1000000];
void add(int from,int to)
{
e[cont].from=from;
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}
void add2(int from,int to)
{
ee[cont2].from=from;
ee[cont2].to=to;
ee[cont2].next=head2[from];
head2[from]=cont2++;
}
void Dfs(int u)
{
vis[u]=1;
for(int k=head[u];k!=-1;k=e[k].next)
{
int v=e[k].to;
if(vis[v]==0)
{
Dfs(v);
}
}
num[sig++]=u;
}
void Dfs2(int u)
{
vis[u]=1;
color[u]=sig;
for(int k=head2[u];k!=-1;k=ee[k].next)
{
int v=ee[k].to;
if(vis[v]==0)
{
Dfs2(v);
}
}
}
void Kosaraju()
{
sig=1;
memset(color,0,sizeof(color));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
Dfs(i);
}
}
sig=0;
memset(vis,0,sizeof(vis));
for(int i=n;i>=1;i--)
{
if(vis[num[i]]==0)
{
sig++;
Dfs2(num[i]);
}
}
for(int i=1;i<=n;i++)
{
for(int k=head[i];k!=-1;k=e[k].next)
{
int vv=e[k].to;
if(color[vv]!=color[i])
{
degree[color[i]]++;
}
}
}
int tot=0;
int tmp=-1;
for(int i=1;i<=sig;i++)
{
if(degree[i]==0)
{
tot++;
tmp=i;
}
}
if(tot==1)
{
int output=0;
for(int i=1;i<=n;i++)
{
if(color[i]==tmp)output++;
}
printf("%d\n",output);
}
else printf("0\n");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
cont=0;cont2=0;
memset(num,0,sizeof(num));
memset(degree,0,sizeof(degree));
memset(vis,0,sizeof(vis));
memset(color,0,sizeof(color));
memset(head,-1,sizeof(head));
memset(head2,-1,sizeof(head2));
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add2(y,x);
}
Kosaraju();
}
}
Time Limit: 2000MS | | Memory Limit: 65536K |
Total Submissions: 29593 | | Accepted: 11981 |
Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is
transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
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
* Line 1: Two space-separated integers, N and M
* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow.
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity.
Source
USACO 2003 Fall
题目大意:给你n头牛,m个关系,每个关系表示a崇拜b,问有多少牛被所有牛所崇拜。
思路:
根据样例可以看出,这个图不是DAG图,而是存在环的有向图,这里怎样处理留到之后来讨论,我们先讨论如何得出结论。
1、如果有这样一个DAG图:
(在DAG图中)我们不难分析,如果其点有出度,那么这个点首先一定就不是被所有牛崇拜的对象,所以如果一个点没有出度,那么这头牛就很有可能被所有牛所崇拜。根据这个图我们还能推出这样一个结论:如果出度为0的牛大于两个,那么就说明被所有牛都崇拜的个数为0,因为这里有两头及以上牛互相没有崇拜关系。
那么如果图变成了这样:
这个时候4就是被所有牛崇拜的对象。
综上所述,在DAG图中,出度为0的节点如果只有一个,那么这个节点就一定是被所有牛崇拜的对象,如果出度为0的节点为0或者是出度为0的节点个数大于等于2,那么就没有牛满足被所有牛崇拜的条件,也就是被所有牛崇拜的牛的个数为0.
2、处理有向环。
这个时候我们做题的目标性就很明确了,如何将一个带有向环的图变成一个DAG图,如果大家有对最小树型图之类的需要缩点的算法有所了解的话,相信大家已经明确了答案,对于一个环,我们可以当做一个点来处理。对于一个有向环,他们其中每两个节点又是强连通的,而且强连通算法又是辣么的快速 ,所以我们这里就使用强连通算法来确定强连通分量(有向环),并在处理过程中,将一个环染色,也就是将一堆点变成了一个点,这样,我们就得到了DAG图。
既然我们这样处理就得到了DAG图,那么AC也就近在眼前了。
3、代码实现
我这里求强连通分量的算法使用的是Kosaraju,两次Dfs,过程中染色,对于每个缩点,不用计较其出边的个数,要不然我们在这里要处理更多麻烦的步骤,我们要统计的是出度为0的点的个数,出度为1,还是出度为20,我们都不关心,所以在这里缩点之后边的缩减我这里就不进行处理了。
AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
int head[100000];
int head2[100000];
struct EdgeNode
{
int from;
int to;
int next;
}e[100000],ee[100000];
int n,m,cont,cont2,sig;
int degree[1000000];
int vis[1000000];
int num[1000000];
int color[1000000];
void add(int from,int to)
{
e[cont].from=from;
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}
void add2(int from,int to)
{
ee[cont2].from=from;
ee[cont2].to=to;
ee[cont2].next=head2[from];
head2[from]=cont2++;
}
void Dfs(int u)
{
vis[u]=1;
for(int k=head[u];k!=-1;k=e[k].next)
{
int v=e[k].to;
if(vis[v]==0)
{
Dfs(v);
}
}
num[sig++]=u;
}
void Dfs2(int u)
{
vis[u]=1;
color[u]=sig;
for(int k=head2[u];k!=-1;k=ee[k].next)
{
int v=ee[k].to;
if(vis[v]==0)
{
Dfs2(v);
}
}
}
void Kosaraju()
{
sig=1;
memset(color,0,sizeof(color));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
Dfs(i);
}
}
sig=0;
memset(vis,0,sizeof(vis));
for(int i=n;i>=1;i--)
{
if(vis[num[i]]==0)
{
sig++;
Dfs2(num[i]);
}
}
for(int i=1;i<=n;i++)
{
for(int k=head[i];k!=-1;k=e[k].next)
{
int vv=e[k].to;
if(color[vv]!=color[i])
{
degree[color[i]]++;
}
}
}
int tot=0;
int tmp=-1;
for(int i=1;i<=sig;i++)
{
if(degree[i]==0)
{
tot++;
tmp=i;
}
}
if(tot==1)
{
int output=0;
for(int i=1;i<=n;i++)
{
if(color[i]==tmp)output++;
}
printf("%d\n",output);
}
else printf("0\n");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
cont=0;cont2=0;
memset(num,0,sizeof(num));
memset(degree,0,sizeof(degree));
memset(vis,0,sizeof(vis));
memset(color,0,sizeof(color));
memset(head,-1,sizeof(head));
memset(head2,-1,sizeof(head2));
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add2(y,x);
}
Kosaraju();
}
}
相关文章推荐
- poj 2186 Popular Cows 强连通量分解模板
- 开源的许可证GPL、LGPL、BSD、Apache 2.0的通俗解释
- linux VMware安装 CentOS6.5 教程
- 腾讯云官方配置 php+nginx (ubuntu 环境)
- Nginx编译安装
- Mysql双主热备+LVS+Keepalived高可用操作记录
- linux 查看某些硬件信息
- 无法解析域名的背后原因是什么?
- linux mysql 操作命令
- CentO S 7 开放端口
- Linux 修改时区 不用重启
- tomcat域名绑定
- Apache通过rewrite限制某个目录---模块
- Apache 禁止指定user_agent---模块
- Apache禁止解析php---模块
- Apache访问控制---模块
- Apache配置防盗链---模块
- 分布式服务协调员zookeeper - 应用场景和监控
- 泰晓科技 +兰大开源社区 +程序动态分析---LINUX内核网站
- RunLoop的深入剖析