E. Chain Email

woc: 关同步流就不能用scanf和printf 了

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 缩点变成DAG图,从原点所在的联通分量开始,dfs遍历子树,找到第一个连通分量大于1 的节点,它和它后面的节点都可以被无限循环到

 

code:

#include<bits/stdc++.h> 

using namespace std;

const int N=100;
const int M=6e3;
int head[N],e[M],ne[M],ha[N];
int dfn[N],low[N],num[N];
int cnt,idex,scc;
int n,m;
bool instack[N],vis[N];
int pre[N];
stack<int> sta;
int p,s,k;
string str[N];
int ca;
void add1(int u,int v){
	e[cnt]=v,ne[cnt]=head[u],head[u]=cnt++;
} 
void add2(int u,int v){
	e[cnt]=v,ne[cnt]=ha[u],ha[u]=cnt++;
} 
void tarjan(int u){
	dfn[u]=low[u]=++idex;
	sta.push(u);
	instack[u]=1;
	int v;
	for(int i=head[u];i!=-1;i=ne[i]){
		v=e[i];
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(instack[v]) low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){
		scc++;
		do{
			v=sta.top();
			sta.pop();
			instack[v]=0;
			pre[v]=scc;
			num[scc]++;
		}while(u!=v);
	}	
}
void dfs(int u,int t){
	if(num[u]>1) t=1;
	if(t) instack[u]=1;
	vis[u]=1;
	int v;
	for(int i=ha[u];i!=-1;i=ne[i]){
		v=e[i];
		if(!vis[v]) dfs(v,t);
	}
}
int main()
{
	int u,v;
	int n;
	cin>>n;
	while(n--){
		ca++;
		scanf("%d%d",&p,&s); 
		for(int i=1;i<=p;i++) head[i]=ha[i]=-1;
		for(int i=1;i<=p;i++) dfn[i]=low[i]=vis[i]=instack[i]=pre[i]=num[i]=0;
		for(int i=1;i<=M;i++) e[i]=ne[i]=0;
		cnt=0,scc=0,idex=0;
		for(int i=1;i<=p;i++){
			cin>>str[i]; 
		}
		for(int i=1;i<=p;i++){
			u=i;
			scanf("%d",&m);
			while(m--){
				scanf("%d",&v);
				add1(u,v);
			}
		}
		for(int i=1;i<=p;i++){
			if(!dfn[i]) tarjan(i); 
		}
//		cout<<scc<<endl;
		for(int i=1;i<=p;i++){
			u=i;
			for(int j=head[i];j!=-1;j=ne[j]){
				v=e[j];
				if(pre[u]!=pre[v]){
					add2(pre[u],pre[v]);
				}
			}
		}
		dfs(pre[s],0);
		printf("Chain Email #%d: \n",ca);
		bool flag=0;
		for(int i=1;i<=p;i++){
			if(instack[pre[i]]){
				flag=1;
				cout<<str[i]<<" ";
			}
		}
		if(!flag) printf("Safe chain email! ");	
		printf("\n\n");
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值