大意:给定一些已有的结论,然后问你最小还需多少添加结论才能证明一个命题。
思路:有向图强连通缩点,然后判断出度与入度的最大值,当scnt == 1时,需特判。 - -!好久木有写强连通分量,生疏了。
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <string> #include <algorithm> using namespace std; const int MAXN = 20010; const int MAXM = 100010; struct Edge { int v, next; }edge[MAXM]; int first[MAXN], stack[MAXN], ins[MAXN], dfn[MAXN], low[MAXN]; int belong[MAXN]; int ind[MAXN], outd[MAXN]; int n, m; int cnt; int scnt, top, tot; void init() { cnt = 0; scnt = top = tot = 0; memset(first, -1, sizeof(first)); memset(dfn, 0, sizeof(dfn)); memset(ins, 0, sizeof(ins)); memset(ind, 0, sizeof(ind)); memset(outd, 0, sizeof(outd)); } void read_graph(int u, int v) { edge[cnt].v = v, edge[cnt].next = first[u]; first[u] = cnt++; } /*强连通分量*/ void dfs(int u) { int v; low[u] = dfn[u] = ++tot; stack[top++] = u; ins[u] = 1; for(int e = first[u]; e != -1; e = edge[e].next) { v = edge[e].v; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(ins[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { scnt++; do { v = stack[--top]; belong[v] = scnt; ins[v] = 0; }while(u != v); } } void Tarjan() { for(int v = 1; v <= n; v++) if(!dfn[v]) dfs(v); } void read_case() { init(); scanf("%d%d", &n, &m); while(m--) { int u, v; scanf("%d%d", &u, &v); read_graph(u, v); } } void solve() { read_case(); Tarjan(); for(int u = 1; u <= n; u++) { for(int e = first[u]; e != -1; e = edge[e].next) { int v = edge[e].v; if(belong[u] != belong[v]) { outd[belong[u]]++; ind[belong[v]]++; } } } int a = 0, b = 0; for(int i = 1; i <= scnt; i++) { if(!ind[i]) a++; if(!outd[i]) b++; } int ans = max(a, b); if(scnt == 1) ans = 0; //特判一下 printf("%d\n", ans); } int main() { int T; scanf("%d", &T); while(T--) { solve(); } return 0; }