bzoj2597

费用流

反过来做,考虑什么情况下不行

对于三个点,当一个点出度为$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\n", 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 ? '\n' : ' ');
        }
    }
    return 0;
}
View Code

 

posted @ 2019-12-06 22:12  19992147  阅读(165)  评论(0编辑  收藏  举报