POJ2168结题报告【强连通分量】

来源:互联网 发布:mac桌面文件复制到u盘 编辑:程序博客网 时间:2024/05/20 18:42
Popular Cows
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 16924 Accepted: 6796

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 31 22 12 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity. 

Source

USACO 2003 Fall

题目大意:牛之间有一个崇拜关系,如A崇拜B。崇拜关系是可以继承的,如果A崇拜B,B崇拜C,那么A同时也会崇拜C(所谓爱屋及乌吧0 0)。现在让你求被所有牛崇拜的牛共有几头。

解题思路:求强连通分量。强连通分量的定义是,处于强连通分量中的任意两个点之间都存在路径。所以如果把崇拜关系抽象成图中的有向边,牛抽象成点,那么处于一个强连通分量中的牛就有这样的关系:他们之间任意两牛之间都有路径,也就是互相崇拜。这样先求出图中的强连通分量,把这些牛分成若干“群”牛,处于同一群牛中的牛是互相崇拜的,而且如果某一群中的某头牛D崇拜另一群中的某头牛,那么这头牛所处的牛群中的每头牛都会崇拜D所崇拜的那头牛所在的牛群中的每头牛。把每个牛群都看成一个图中的点,所以只要找到入度为0的牛群即可,如果只存在一个入读为0的牛群那么答案就是这个牛群的牛的个数,如果存在2个或2个以上的入读为0的牛群,那么答案就是0了(因为这些牛群相互不崇拜)。

(因为刚刚学习强连通分量,三个算法都试着是实现了下)

代码:kosaraju
#include<cstdio>#include<cstring>#include<queue>#include<stack>using namespace std;#define INF 0x7ffffff#define MAX_NODE 10010#define MAX_SIDE 500010int node[MAX_NODE];int rnode[MAX_NODE];struct SIDE{    int to,next;    SIDE(int to,int next):to(to),next(next){}    SIDE(){}}side[2*MAX_SIDE];int top;void add_side(int u,int v){    side[top]=SIDE(v,node[u]);    node[u]=top++;    side[top]=SIDE(u,rnode[v]);    rnode[v]=top++;}bool visit[MAX_NODE];int time[MAX_NODE];int witch[MAX_NODE];int num[MAX_NODE];int n,m;int q[MAX_NODE];int mark;int current;int rdfs(int u){    //printf("rdfs %d\n",u);    visit[u]=true;    for(int i=rnode[u];i!=-1;i=side[i].next){        int v=side[i].to;        if(!visit[v]){            rdfs(v);        }    }    q[mark++]=u;}int dfs(int u){    //printf("dfs %d\n",u);    visit[u]=true;    witch[u]=current;    num[current]++;    for(int i=node[u];i!=-1;i=side[i].next){        int v=side[i].to;        if(!visit[v]){            dfs(v);        }    }}int kosaraju(){    memset(visit,0,sizeof(visit));    mark=1;    for(int i=1;i<=n;i++){        if(!visit[i]){            rdfs(i);        }    }    memset(visit,0,sizeof(visit));    memset(num,0,sizeof(num));    current=0;    for(int i=n;i;i--){        int u=q[i];        if(!visit[u]){            dfs(u);            current++;        }    }    //printf("current %d\n",current);}bool out[MAX_NODE];int solve(){    memset(out,0,sizeof(out));    for(int u=1;u<=n;u++){        if(out[witch[u]])continue;        for(int i=node[u];i!=-1;i=side[i].next){            int v=side[i].to;            if(witch[v]!=witch[u]){                out[witch[u]]=true;                break;            }        }    }    int r=0;    for(int i=0;i<current;i++){        if(!out[i]){           if(r)return 0;            r=num[i];        }    }    return r;}int main(){    scanf("%d%d",&n,&m);    memset(node,-1,sizeof(node));    memset(rnode,-1,sizeof(rnode));    top=0;    for(int i=0;i<m;i++){        int from,to;        scanf("%d%d",&from,&to);        add_side(from,to);    }    kosaraju();    printf("%d\n",solve());    return 0;}

代码:tarjan
#include<cstdio>#include<cstring>#include<stack>using namespace std;#define INF 0x7ffffff#define MAX_NODE 10100#define MAX_SIDE 50100int node[MAX_NODE];struct SIDE{    int to,next;    SIDE(int to,int next):to(to),next(next){}    SIDE(){}}side[MAX_SIDE];int top;void add_side(int u,int v){    side[top]=SIDE(v,node[u]);    node[u]=top++;}int num[MAX_NODE];int low[MAX_NODE];int dfn[MAX_NODE];stack<int>q;int time;int sum;void dfs(int u){    int v;    low[u]=dfn[u]=time++;    q.push(u);    for(int i=node[u];i!=-1;i=side[i].next){        v=side[i].to;        if(!dfn[v]){            dfs(v);        }        if(dfn[v]!=-1){            low[u]=min(low[u],low[v]);        }    }    if(low[u]==dfn[u]){        do{            v=q.top();            q.pop();            dfn[v]=-1;            num[sum]++;            low[v]=sum;        }while(v!=u);        sum++;    }}int n,m;void tarjan(){    sum=0,time=1;    memset(num,0,sizeof(num));    memset(dfn,0,sizeof(dfn));    while(!q.empty())q.pop();    for(int i=1;i<=n;i++){        if(!dfn[i])dfs(i);    }}bool out[MAX_NODE];int solve(){    memset(out,0,sizeof(out));    for(int u=1;u<=n;u++){        if(out[low[u]])continue;        for(int i=node[u];i!=-1;i=side[i].next){            int v=side[i].to;            if(low[v]!=low[u]){                out[low[u]]=true;                break;            }        }    }    int r=0;    for(int i=0;i<sum;i++){        if(!out[i]){           if(r)return 0;            r=num[i];        }    }    return r;}int main(){    scanf("%d%d",&n,&m);    memset(node,-1,sizeof(node));    top=0;    for(int i=0;i<m;i++){        int from,to;        scanf("%d%d",&from,&to);        add_side(from,to);    }    tarjan();    printf("%d\n",solve());    return 0;}

代码:gabow
#include<cstdio>#include<cstring>#include<stack>using namespace std;#define MAX_NODE 10100#define MAX_SIDE 50100int node[MAX_NODE];struct SIDE{    int to,next;    SIDE(int to,int next):to(to),next(next){}    SIDE(){}}side[MAX_SIDE];int top;void add_side(int u,int v){    side[top]=SIDE(v,node[u]);    node[u]=top++;}stack<int>q;stack<int>temp;int dfn[MAX_NODE];int num[MAX_NODE];int belong[MAX_NODE];int time;int sum;int m,n;void dfs(int u){    int v;    dfn[u]=time++;    q.push(u);temp.push(u);    for(int i=node[u];i!=-1;i=side[i].next){        v=side[i].to;        if(!dfn[v])dfs(v);        else if(!belong[v]){            while(dfn[temp.top()]>dfn[v])temp.pop();        }    }    if(u==temp.top()){        sum++;        temp.pop();        do{            v=q.top();q.pop();            num[sum]++;            belong[v]=sum;        }while(v!=u);    }}void gabow(){    sum=0;time=1;    while(!q.empty())q.pop();    while(!temp.empty())temp.pop();    memset(num,0,sizeof(num));    memset(belong,0,sizeof(belong));    memset(dfn,0,sizeof(dfn));    for(int i=1;i<=n;i++){        if(!dfn[i])dfs(i);    }}bool out[MAX_NODE];int solve(){    memset(out,0,sizeof(out));    int v;    for(int u=1;u<=n;u++){        if(out[belong[u]])continue;        for(int i=node[u];i!=-1;i=side[i].next){            v=side[i].to;            if(belong[u]!=belong[v]){                out[belong[u]]=true;                break;            }        }    }    int r=0;    for(int i=1;i<=sum;i++){        if(!out[i]){            if(r)return 0;            r=num[i];        }    }    return r;}int main(){    top=0;    memset(node,-1,sizeof(node));    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        int from,to;        scanf("%d%d",&from,&to);        add_side(from,to);    }    gabow();    printf("%d\n",solve());    return 0;}