UCF Local Programming Contest 2014 E. Chain Email (tarjan强联通分量)

整理的算法模板:ACM算法模板总结(分类详细版)

A chain email is an email that people receive and then forward to all of their friends. This sort of email is very common amongst elderly people, who have notably bad memories. Elderly people’s memories are so bad that if they ever receive a chain email they will forward it to all of their contacts. This can become very problematic when elderly people continually send the same email to each other. For instance, if two people have each other in their contacts and if either of them receive a chain email they will continually send the email to each other back and forth forever. Email companies are worried that this will result in a massive amount of storage loss on their servers and have asked you to determine if a specific person were to start a chain email, who would receive that email forever.

The Problem:

Given each elderly person’s contacts and which elderly person will be starting a chain email, determine who will be indefinitely receiving emails.

The Input:

The first line of the input is a positive integer, n, indicating the number of scenarios that your program will have to analyze. Following this will be the description of each scenario. The first line of each scenario will have two single-space-separated integers, p (1 ≤ p ≤ 50), indicating the number of people who use the email service and, s (1 ≤ s ≤ p), indicating the source of the chain email, where each person is labeled from 1 to p. Following this will be a single line with the names of all of the people, from person 1 to person p, who use the email service, each separated by exactly one space. All names will contain alphabetic characters only and be between 1 and 19 characters (inclusive) in length. Following this will be p lines. The ith line will describe the contact list of the ith person. This description will consist of an integer, m (0 ≤ m < p), indicating the number of contacts this person has, followed by the 1-based index of each of the contacts, each separated by exactly one space. It's guaranteed that no one will contain themselves as a contact.

The Output:

The first line of the output for each scenario should be “Chain Email #d:”, where d is the scenario number, starting with 1. Following this should be a line containing the names of all of the people who will infinitely receive chain emails, assuming that everyone continually forwards the email to all of their contacts. Each name should be followed by a space. List these contacts in the order that they appear in the input. If no one will infinitely receive chain emails, then print “Safe chain email!” instead. Leave a blank line after the output for each data set. Follow the format illustrated in Sample Output.

样例输入复制

3
3 1
James Sarah John 
2 2 3       
2 1 3       
2 1 2 
3 1 
James Sarah John 
2 2 3 
0 
0 
6 3 
Ali Matt Glenn Sumon Arup Chris 
2 3 5 
0 
1 4 
1 1 
1 2 
2 5 4 

样例输出复制

Chain Email #1: 
James Sarah John 

Chain Email #2: 
Safe chain email! 

Chain Email #3: 
Ali Matt Glenn Sumon Arup 

昨天的训练赛没打,。。。。。看到刚好有一道练习tarjan的题,练练手吧;

 思路:

首先能够无限接受邮件的点分两类,一类是环里面的点,一类是由环中的点出发所能到达的点;

用tarjan处理强连通块,并且缩点建立新图,然后由给出的起点出发,标记走过的所有连通块,则连通块内的所有点都符合条件;然后从这些连通块中任意一点出发所能到达的点也都符合条件;(注意只有一个点的强连通分量不能接受也不能发送邮件,注意特判即可);

#include 
using namespace std;
const int N=55,M=3000;
map mp;
map mpp;
map mp_id;
int h[N],hs[N],e[M],ne[M],idx;
int dfn[N],low[N],stk[N],in_stk[N],id[N],size_scc[N];
int scc_cnt,timestamp,top,n,x,flag;
vector v[N];
void add(int h[],int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++ timestamp;
    stk[ ++ top] = u, in_stk[u] = true;
 
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (!dfn[j])
        {
            tarjan(j);
            low[u] = min(low[u], low[j]);
        }
        else if (in_stk[j])
            low[u] = min(low[u], dfn[j]);
    }
 
    if (dfn[u] == low[u])//如果记录的两个时间戳相等,则说明u为强连通块的最高点
    {
        ++ scc_cnt;
        int y;
        do {
            y = stk[top -- ];
            in_stk[y] = false;
            id[y] = scc_cnt;
            size_scc[scc_cnt]++;
            v[scc_cnt].push_back(y);
        } while (y != u);
    }
}
void init()
{
    flag=0;
    memset(h,-1,sizeof h);
    memset(hs,-1,sizeof hs);
    top=timestamp=scc_cnt=idx=0;
    mp.clear();
    mpp.clear();
    mp_id.clear();
    for(int i=0;i<=n;i++) stk[i]=in_stk[i]=id[i]=low[i]=dfn[i]=size_scc[i]=0,v[i].clear();
}
void dfs_hs(int ver)
{ 
    if(size_scc[ver]>1) mp_id[ver]=1,flag=1;
    for(int i=hs[ver];~i;i=ne[i])
    {
        int j=e[i];
        dfs_hs(j);
    }
}
void dfs_h(int u)
{
    if(mpp[u]) return ;
    mpp[u]++;
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        dfs_h(j);
    }
}
int main()
{
    int t;
    cin >>t;
    int idd=0;
    while(t--)
    {
        idd++;
        printf("Chain Email #%d:\n",idd);
        cin >>n>>x;
        init();
        for(int i=1;i<=n;i++)
        {
            string s;cin >>s;mp[i]=s;
        }
        for(int i=1;i<=n;i++)
        {
            int cnt;
            cin >>cnt;
            while(cnt--)
            {
                int u;
                cin >>u;
                add(h,i,u);
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i]) tarjan(i);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=h[i];~j;j=ne[j])
            {
                int k=e[j];
                int a=id[i],b=id[k];
                if(a!=b) add(hs,a,b);
            }
        }
        
        dfs_hs(id[x]);
        if(flag==0) 
        {
            printf("Safe chain email!\n\n");
            continue;
        }
        for(int i=1;i<=scc_cnt;i++)
            if(mp_id[i])
                for(int j=0;j

 

你可能感兴趣的:(基础算法——图论,有向图的强连通分量)