传递闭包
二元关系是一个点选了另一个点就不能选
拆点,求最大独立集
二分图的最大独立集=点数-最大匹配。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define in(u) u
#define out(u) u + n
#define maxn 1000010
using namespace std;
int n, m;
const int inf = 0x7fffffff;
struct Edge{
int to, next, w;
}edge[maxn << 1];
int h[210], cnt = 1;
void add(int u, int v, int w){
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
edge[cnt].w = w;
h[u] = cnt;
swap(u, v), w = 0;
cnt ++;
edge[cnt].to = v;
edge[cnt].next = h[u];
edge[cnt].w = w;
h[u] = cnt;
}
queue<int>Q;
int d[10010], S, T;
bool BFS(){
memset(d, -1, sizeof d);
Q.push(S);d[S] = 0;
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int i = h[u]; i; i = edge[i].next){
if(!edge[i].w)continue;
int v = edge[i].to;
if(d[v] == -1){
d[v] = d[u] + 1;
Q.push(v);
}
}
}return d[T] != -1;
}
int DFS(int x, int a){
if(x == T || a == 0)return a;
int used = 0, f;
for(int i = h[x]; i; i = edge[i].next){
int v = edge[i].to;
if(d[v] == d[x] + 1){
f = DFS(v, min(a - used, edge[i].w));
edge[i].w -= f;
edge[i ^ 1].w += f;
used += f;
if(used == a)return used;
}
}
if(used == 0)d[x] = -1;
return used;
}
int Dinic(){
int ans = 0;
while(BFS())
ans += DFS(S, inf);
return ans;
}
bool G[210][210];
int main(){
scanf("%d%d", &n, &m);
S = 0, T = n * 2 + 1;
int u, v;
for(int i = 1; i <= n; i ++){
add(S, in(i), 1);
add(out(i), T, 1);
}
for(int i = 1; i <= m; i ++){
scanf("%d%d", &u, &v);
G[u][v] = 1;
}
for(int k = 1; k <= n; k ++)
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
G[i][j] |= G[i][k] & G[k][j];
for(int u = 1; u <= n; u ++)
for(int v = 1; v <= n; v ++)
if(G[u][v])add(in(u), out(v), 1);
printf("%d\n", n - Dinic());
return 0;
}