思路:根据题目的意思,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; }