题目说给出一些子集,如果A是B的子集,B是A的子集,那么A和B就是相等的,然后给出n个集合m个关系,m个关系表示u是v的子集,问你最小再添加多少个关系可以让这n个集合都是相等的
如果这n个几个都是互相相等的,那么就等于是这n个集合看成点以后,构成的图是一个强连通图,那么就是说在加多少边让这个图变成强联通图。
先缩点然后做判断
1,如果原本的图本来就是强联通的,那么答案就是0
2.如果原本的图不是强联通的,那就去判断缩完以后的点的入度和出度,取入度为0的和出度为0的点数的最大值,就是最小需要加的边
#include<map> #include<set> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define lowbit(x) (x & (-x)) typedef unsigned long long int ull; typedef long long int ll; const double pi = 4.0*atan(1.0); const int inf = 0x3f3f3f3f; const int maxn = 20005; const int maxm = 50005; const int mod = 10007; using namespace std; int n, m, tol, T; int cnt, sz, top; struct Node { int u, v; int next; }; Node node[maxm]; int head[maxn]; int dfn[maxn]; int low[maxn]; int ind[maxn]; int oud[maxn]; int sta[maxn]; int point[maxn]; bool vis[maxn]; void init() { tol = cnt = top = sz = 0; memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); memset(ind, 0, sizeof ind); memset(oud, 0, sizeof oud); memset(vis, 0, sizeof vis); memset(head, -1, sizeof head); memset(point, 0, sizeof point); } void addnode(int u, int v) { node[tol].u = u; node[tol].v = v; node[tol].next = head[u]; head[u] = tol++; } void dfs(int u) { int v; dfn[u] = low[u] = ++cnt; sta[sz++] = u; vis[u] = true; for(int i=head[u]; ~i; i=node[i].next) { v = node[i].v; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(vis[v]) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { top++; do { v = sta[--sz]; point[v] = top; vis[v] = false; } while(v != u); } } void tarjan() { for(int u=1; u<=n; u++) { if(!dfn[u]) dfs(u); } } void solve() { for(int u=1; u<=n; u++) { for(int i=head[u]; ~i; i=node[i].next) { int v = node[i].v; if(point[u] != point[v]) { ind[point[v]]++; oud[point[u]]++; } } } } int main() { while(~scanf("%d%d", &n, &m)) { init(); int u, v; for(int i=1; i<=m; i++) { scanf("%d%d", &u, &v); addnode(u, v); } tarjan(); // for(int i=1; i<=n; i++) printf("!!!!%d %d ", i, point[i]); if(top == 1) { printf("0 "); continue; } solve(); int ans1=0, ans2=0; memset(vis, 0, sizeof vis); for(int i=1; i<=top; i++) { if(ind[i] == 0) ans1++; if(oud[i] == 0) ans2++; } printf("%d ", max(ans1, ans2)); } return 0; }