费用流
反过来做,考虑什么情况下不行
对于三个点,当一个点出度为$2$时不形成三元环
设$x$度数为$d_x$,那么不形成的三元环就是$frac{d_x(d_x-1)}{2}$
建图,一边是点,一边是边,边向汇连容量为$1$费用为$0$的边
点连向对应边
原点向点连$n-1$条边,费用递增
跑最小费用流,总数减去就是答案
#include <bits/stdc++.h> using namespace std; const int maxn = 1e4 + 5, inf = 0x3f3f3f3f; struct edge { int nxt, to, f, c; } e[maxn * 100]; int n, m, k, source, sink, cnt = 1; int head[maxn], pree[maxn], Prev[maxn], vis[maxn], d[maxn]; inline void link(int u, int v, int f, int c) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].f = f; e[cnt].to = v; e[cnt].c = c; } inline void insert(int u, int v, int f, int c) { link(u, v, f, c); link(v, u, 0, -c); } bool spfa() { memset(d, -1, sizeof(d)); d[source] = 0; queue<int> q; q.push(source); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; i; i = e[i].nxt) { if(e[i].f && (d[e[i].to] > d[u] + e[i].c || d[e[i].to] == -1)) { pree[e[i].to] = i; Prev[e[i].to] = u; d[e[i].to] = d[u] + e[i].c; if(vis[e[i].to] == 0) { q.push(e[i].to); vis[e[i].to] = 1; } } } } return ~d[sink]; } inline int Edmonds_Karp() { int ans = 0; while(spfa()) { int now = sink, delta = inf; while(now != source) { delta = min(delta, e[pree[now]].f); now = Prev[now]; } now = sink; while(now != source) { e[pree[now]].f -= delta; e[pree[now] ^ 1].f += delta; now = Prev[now]; } ans += delta * d[sink]; } return ans; } int a[105][105], id[105][105]; int main() { scanf("%d", &n); source = maxn - 2; sink = maxn - 1; for(int i = 0; i < n; ++i) { for(int j = 0; j < n; ++j) { scanf("%d", &a[i][j]); } } for(int i = 0; i < n; ++i) { for(int j = 0; j < n - 1; ++j) { insert(source, i, 1, j); } } int tot = n; for(int i = 0; i < n; ++i) { for(int j = 0; j < i; ++j) { insert(++tot, sink, 1, 0); if(a[i][j] == 0 || a[i][j] == 2) { insert(i, tot, 1, 0); id[j][i] = cnt - 1; } if(a[i][j] == 1 || a[i][j] == 2) { insert(j, tot, 1, 0); id[i][j] = cnt - 1; } } } int ans = n * (n - 1) * (n - 2) / 6; printf("%d ", ans - Edmonds_Karp()); for(int i = 0; i < n; ++i) { for(int j = 0; j < n; ++j) { if(i == j) { printf("0"); } else { printf("%d", !id[i][j] || e[id[i][j]].f ? 0 : 1); } printf("%c", j == n - 1 ? ' ' : ' '); } } return 0; }