poj1904(强联通分量)

一道很好的题。

题目所给的名单是很有用的,首先按照王子陪女孩的方式 建边,然后名单中的女孩对应王子建一条反向边。

为什么这样做呢? 其实就是将名单中王子和女孩捆绑成一个点,因为王子到女孩有一条边,名单中的女孩到王子也有一天边,那么着两个点就是互通的,那么久相当于他们是同一个点一样,在建图的时候能到达王子的都能到达名单中的女号,能到达名单中的女孩的都能到达王子。这样动手画下这题的草图(名单中的女孩和王子是一个点)很容易看出之间的关系,分析一下,发现如果是同一个联通分量里面的点刚好满足题目的要求,于是这题就用强联通分量求解,在输出解的时候就输出王子喜欢的女孩并且这个女孩是和王子在同一个联通分量中。

开始用set存超时,然后用读入读出外挂勉强过了,用优先队列速度质的提升,将近快了10倍。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef long long ll;
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
const int oo=0x3f3f3f3f;
const int MOD=1000000007;
const int maxn=4100;
const int maxm=310000;
struct EDGE{
    int v,next,c,f;
}E[maxm];
int head[maxn],tol;
int low[maxn],dfn[maxn],instack[maxn],Stack[maxn],id[maxn];
int g_cnt,top,ID;
int ans[2005][2005],num[2005];
struct Node{
    int n;
    Node(int x){ n=x; }
    bool operator<(const Node& a)const{
        return a.n<n;
    }
};

void read(int &num)
{
    char in;
    bool neg=false;
    while(((in=getchar()) > '9' || in<'0') && in!='-') ;
    if(in=='-')
    {
        neg=true;
        while((in=getchar()) >'9' || in<'0');
    }
    num=in-'0';
    while(in=getchar(),in>='0'&&in<='9')
        num*=10,num+=in-'0';
    if(neg)
        num=0-num;
}

void write(int x){
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}

void Init(){
    memset(head,-1,sizeof head);
    tol=0;
    memset(low,0,sizeof low);
    memset(dfn,0,sizeof dfn);
    memset(instack,0,sizeof instack);
    g_cnt=top=ID=0;
}

void add_edge(int u,int v){
    E[tol].v=v;
    E[tol].next=head[u];
    head[u]=tol++;
}

void Tarjan(int u){
    dfn[u]=low[u]=++g_cnt;
    Stack[++top]=u;
    instack[u]=1;
    int v;
    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(instack[v]&&dfn[v]<low[u])
            low[u]=dfn[v];
    }
    if(dfn[u]==low[u]){
        ID++;
        do{
            v=Stack[top--];
            instack[v]=0;
            id[v]=ID;
        }while(u!=v);
    }
}

void gao(int n){
    priority_queue<Node>q;
    for(int i=1;i<=n;i++){
        int u=i;
        for(int j=head[u];j!=-1;j=E[j].next){
            int v=E[j].v;
            if(id[u]==id[v]&&v>n)
                q.push(Node(v-n));
        }
        printf("%d",q.size());
        while(!q.empty()){
            Node ans=q.top();
            q.pop();
            putchar(' ');
            write(ans.n);
        }
        puts("");
    }
}

int main(){
    //freopen("E:\\read.txt","r",stdin);
    int n,u,v,k;
    while(scanf("%d",&n)!=EOF){
        Init();
        for(int i=1;i<=n;i++){
            read(k);
            u=i;
            for(int j=1;j<=k;j++){
                read(v);
                v+=n;
                add_edge(u,v);
            }
        }
        for(int i=1;i<=n;i++){
            u=i;
            read(v);
            v+=n;
            add_edge(v,u);
        }
        for(int i=1;i<=2*n;i++)if(!dfn[i])Tarjan(i);
        gao(n);
    }
    return 0;
}
/*
4
2 1 2
2 1 2
2 2 3
2 3 4
1 2 3 4
*/


你可能感兴趣的:(算法,poj,Tarjan)