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 <bits/stdc++.h>
using namespace std;
const int N=55,M=3000;
map<int,string> mp;
map<int,int> mpp;
map<int,int> 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<int> 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<v[i].size();j++)
                    dfs_h(v[i][j]);
        for(int i=1;i<=n;i++)
            if(mpp[i]) cout <<mp[i]<<" ";
        printf("\n\n");
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章