uva12167等价性证明

思路:根据题目的意思,a,b,c,d等命题等价就是在推导(逻辑)上可以相互推导出对方,如a->b->c->d->a显然此时可以相互推导出来,把这个放到图上来看就是一个强连通分量,

题目问的是最少还需要添加几个关系可以是的图为一个等价图 == 强连通图;

那么我们就先把已经可以相互推导出来的点缩成一个点,然后就是一个DAG图了,加下来就是看入度为0的点与出度为0 的点的个数了,注意原图已经连通的情况。

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2015
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof a)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
inline int Readint(){
	char c = getchar();
	while(!isdigit(c)) c = getchar();
	int x = 0;
	while(isdigit(c)){
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x;
}
const int maxn = 2e4 + 10;
int top,scc_cnt;
stack<int> s;
vector<int> G[maxn];
int low[maxn],pre[maxn],sccno[maxn],in[maxn],out[maxn];
void dfs(int u){
	pre[u] = low[u] = ++top;
	s.push(u);
	for (int i = 0;i < G[u].size();++i){
		int v = G[u][i];
		if (!pre[v]){
			dfs(v);
			low[u] = min(low[u],low[v]);
		}else if (!sccno[v]){
			low[u] = min(low[u],pre[v]);
		}
	}
	if (low[u] == pre[u]){
		scc_cnt++;
		for (;;){
			int x = s.top();
			sccno[x] = scc_cnt;
			s.pop();
			if (x == u) break;
		}
	}
}
void find_scc(int n){
	top = scc_cnt = 0;
	memset(sccno, 0,sizeof sccno);
	memset(pre, 0,sizeof pre);
	for (int i = 1;i <= n;i++)
		if (!pre[i]) dfs(i);
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	int T,n,m;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for (int i = 1;i <= n;i++)
			G[i].clear();
		int a,b;
		for (int i = 1;i <= m;i++){
			scanf("%d%d",&a,&b);
			G[a].push_back(b);//a->b;
		}
		find_scc(n);
		memset(in, 0,sizeof in);
		memset(out, 0,sizeof out);
		for (int i = 1;i <= n;i++){
			for (int j = 0;j < G[i].size();j++){
				int v = G[i][j];
				if (sccno[i] != sccno[v]){
					in[sccno[v]]++;
					out[sccno[i]]++;
				}
			}
		}
		a = 0,b = 0;
		for (int i = 1;i <= scc_cnt;i++){
			// printf("in:%d->%d\n",i,in[i]);
			// printf("out:%d->%d\n",i,out[i]);
			if (in[i] == 0) a++;
			if (out[i] == 0) b++;
		}
		if (scc_cnt == 1) printf("%d\n",0);
		else printf("%d\n",max(a,b));
	}
	return 0;
}


你可能感兴趣的:(图论,uva,强连通分量)