给定n个命题之间的已经证明的关系如 a b表示已经证明蕴含式a→b,要求还需要再作多少次证明使得所有的命题都是等价的.将每个命题看成一个点,已经证明的命题之间连一条边,问题转化为添加多少条单向边使得图成为一个强连通分量.
先求出所有的强连通分量,然后缩点构成一个SCC图,统计其中入度为0的点个数a,以及出度为0的点的个数b,max(a,b)就是需要再作的证明.注意当图一开始就是强连通时,不需要作出证明了.
来自刘汝佳算法训练指南代码:
#include <iostream> #include <sstream> #include <cstdio> #include <climits> #include <cstring> #include <cstdlib> #include <string> #include <stack> #include <map> #include <cmath> #include <vector> #include <queue> #include <algorithm> #define esp 1e-6 #define pi acos(-1.0) #define pb push_back #define mp(a, b) make_pair((a), (b)) #define in freopen("in.txt", "r", stdin); #define out freopen("out.txt", "w", stdout); #define print(a) printf("%d ",(a)); #define bug puts("********))))))"); #define stop system("pause"); #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) #define pragma comment(linker, "/STACK:102400000, 102400000") #define inf 0x0f0f0f0f using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int, int> pii; typedef vector<pii,int> VII; typedef vector<int>:: iterator IT; const int maxn = 22222; int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt; int in0[maxn], out0[maxn]; VI g[maxn]; stack<int> S; void dfs(int u) { S.push(u); lowlink[u] = pre[u] = ++dfs_clock; for(int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if(!pre[v]) { dfs(v); lowlink[u] = min(lowlink[u], lowlink[v]); } else if(!sccno[v]) { lowlink[u] = min(lowlink[u], pre[v]); } } if(lowlink[u] == pre[u]) { scc_cnt++; for(;;) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc(int n) { memset(pre, 0, sizeof(pre)); memset(sccno, 0, sizeof(sccno)); dfs_clock = scc_cnt = 0; for(int i = 0; i < n; i++) if(!pre[i]) dfs(i); } int main(void) {in int n, m; int T; for(int t = scanf("%d", &T); t <= T; t++) { for(int i = 0; i < maxn; i++) g[i].clear(); memset(in0, 1, sizeof(in0)); memset(out0, 1, sizeof(out0)); scanf("%d%d", &n, &m); while(m--) { int u, v; scanf("%d%d", &u, &v); u--, v--; g[u].pb(v); } find_scc(n); for(int u = 0; u < n; u++) for(int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if(sccno[v] != sccno[u]) in0[sccno[v]] = out0[sccno[u]] = 0; } int a = 0, b= 0; for(int i = 1; i <= scc_cnt; i++) { if(in0[i]) a++; if(out0[i]) b++; } int ans = 0; if(scc_cnt != 1) ans = max(a, b); printf("%d ",ans); } return 0; }