POJ-2186 Popular Cows 强联通+缩点

Popular Cows
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 38116   Accepted: 15533

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 3
1 2
2 1
2 3

Sample Output

1

题意就是把这个图中的凡是拥有传递关系的点 一直传递过去 如果能够说除了自己之外其他所有点都能传递到某些点的话 就输出这些传递目标点的数量


分析:可以发现 凡是强联通的点 都可以看成一个点 然后强联通分量内的所有点 他们的连通性都可以作为一个点来看待 

所以相当于把这个联通块看作一个点 然后我们把这些点都缩点后 所得到的是一个有向无环图 而这个图中的所有的点 有可能是多个点 所以我们缩点后如果这个图中出度为0的点只有一个 说明那一个点 就是符合题目要求的点 如果有多个点 就不符合题目要求 因为出度为0的点 有多个 那么说明这些点 没有可能互相传递 所以这种情况下输出0

tarjan是基于一个联通块内只有一个点的dfn和low相等的算法 并且每个联通块内的所有点的low都等于这个联通块时间戳最小的点的low 

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {
	static final int maxn = 100010;
	static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
	static ArrayList<Integer> gra[] = new ArrayList[maxn];
	static boolean bok[] = new boolean[maxn];
	static int dfn[] = new int[maxn];
	static int low[] = new int[maxn];
	static int ind = 0, n, m, tag;
	static int id[] = new int[maxn];
	static int cnt[] = new int[maxn];
	static ArrayDeque<Integer> S = new ArrayDeque<Integer>();
	static int[] out1 = new int[maxn];
	static void dfs(int x, int f) {
		dfn[x] = low[x] = ++ind;
		S.push(x);
		bok[x] = true;
		for (int i = 0; i < gra[x].size(); i++) {
			int t = gra[x].get(i);
			if (dfn[t]==0) {// 由于这里之前写的是!bok[i]导致以前计算过的量 也重新计算所以这里发生错误
				dfs(t, x);
				low[x] = Math.min(low[t], low[x]);
			} else if(bok[t])//如果入栈过 进行计算 没有入栈 说明这个点曾经计算过在别的联通块内 如果这个点在别的联通块内  
                                // 不要让这个结果影响当前点的计算 
				low[x] = Math.min(dfn[t], low[x]);
		}
		if (low[x] == dfn[x]){
			int tot = 0;
			id[x] = ++tag;
			while (true) {
				int t = S.peek();
				S.pop();
				tot++;
				id[t] = tag;
				cnt[tag]++;
				bok[t] = false;
				if (t == x)
					break;
			}
		}
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(new BufferedInputStream(System.in));
		while (sc.hasNext()) {
			n = sc.nextInt();
			m = sc.nextInt();
			//
			for (int i = 1; i <= n; i++) {
				if (gra[i] == null)
					gra[i] = new ArrayList<Integer>();
				gra[i].clear();
			}
			
			Arrays.fill(dfn, 0);
			Arrays.fill(low, 0);
			Arrays.fill(cnt, 0);
			Arrays.fill(out1, 0);
			tag = ind = 0;

			for (int i = 1; i <= m; ++i) {
				int s, e;
				s = sc.nextInt();
				e = sc.nextInt();
				gra[s].add(e);
			}

			for (int i = 1; i <= n; i++) {
				if (dfn[i] == 0) {
					S.clear();
					dfs(i, -1);
				}
			}

			int ans = 0;
			for (int i = 1; i <= n; i++) {
				for (int j = 0; j < gra[i].size(); j++) {
					int t = gra[i].get(j);
					if (id[i] != id[t]) {
						out1[id[i]]++;
					}
				}
			}
			
			int res=0;
			for(int i=1;i<=tag;i++) {
				if(out1[i]==0) {
					ans++;
					res = cnt[i];
				}
			}
			if (ans == 1)
				out.println(res);
			else
				out.println(0);
			out.flush();
		}
	}
}






猜你喜欢

转载自blog.csdn.net/qq_33859479/article/details/80421264
今日推荐