BZOJ 2597: [Wc2007]剪刀石头布

竞赛图三元环个数为 \(\binom{n}{3}-\sum\limits_{i=1}^n \binom{deg_i}{2}\)
即为最小化 \(\sum\limits_{i=1}^n \binom{deg_i}{2}\)
考虑费用流
给每个比赛新建一个点 \(C_{i,j}\),若胜负关系已确定,则 \(C_{i,j} \to w\)\(w\) 表示赢的那一方,连一条容量为 \(1\),费用为 \(0\) 的边
否则向双方都连一条容量为 \(1\),费用为 \(0\) 的边
\(S \to C_{i,j}\) 连一条容量为 \(1\),费用为 \(0\) 的边
\(i \to T\)\(n\) 条容量为 \(1\),费用分别为 \(0\dots n-1\) 的边即可
因为最小费用最大流优先走过费用小的边,那么费用之和也等于 \(\binom{deg_i}{2}\)

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<ll, int>
#define SZ(x) ((int)(x).size())
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) / 2)
#define lowbit(i) ((i) & (-i))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=((b)-1);i>=(a);i--)
#define Edg int ccnt=1,head[N],to[E],ne[E];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[E],ne[E],c[E];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1000000007, INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2, int mod = MOD) {int ans = 1; for (; b; a = 1LL * a * a % mod, b >>= 1)if (b & 1)ans = 1LL * ans * a % mod; return ans % mod;}
template<class T>T gcd(T a, T b) { while (b) { a %= b; std::swap(a, b); } return a; }
template<class T>bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<class T>bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

const int N = 1e4 + 7, E = 1e5 + 7, V = 111;
int point[V][V], cnt, n;
char str[V];
char res[V][V];
Edgc
bool inq[N];
int f[E], path[N], dis[N];
int que[E];
inline void add(int u, int v, int ff, int cc) {
    addd(u, v, cc); f[ccnt] = ff;
    addd(v, u, -cc); f[ccnt] = 0;
}

bool spfa(int s, int t) {
    rep (i, 0, t + 1) dis[i] = INF, path[i] = inq[i] = 0;
    int l = 0, r = 0;
    que[r++] = s;
    dis[s] = 0;
    inq[s] = 1;
    while (l ^ r) {
        int u = que[l++];
        inq[u] = 0;
        es (u, i, v) {
            if (f[i] && chkmin(dis[v], dis[u] + c[i])) {
                path[v] = i;
                if (!inq[v]) inq[v] = 1, que[r++] = v;
            }
        }
    }
    return dis[t] != INF;
}

std::pii solve(int s, int t) {
    std::pii ans(0, 0);
    while (spfa(s, t)) {
        int x = INF;
        for (int i = path[t]; i; i = path[to[i ^ 1]]) x = std::min(x, f[i]);
        for (int i = path[t]; i; i = path[to[i ^ 1]]) f[i] -= x, f[i ^ 1] += x;
        ans.fi++; ans.se += x * dis[t];
    }
    return ans;
}

int main() {
#ifdef LOCAL
    freopen("ans.out", "w", stdout);
#endif
    scanf("%d", &n);
    cnt = n;
    int s = 0;
    rep (i, 1, n + 1) {
        rep (j, i + 1, n + 1) {
            point[i][j] = ++cnt;
            add(s, point[i][j], 1, 0);
        }
    }
    int t = ++cnt;
    rep (i, 1, n + 1) {
        rep (j, 0, n) add(i, t, 1, j);
        rep (j, 1, n + 1) {
            int x;
            scanf("%d", &x);
            res[i][j] = x;
            if (!point[i][j]) continue;
            if (x == 0) {
                add(point[i][j], j, 1, 0);
            } else if (x == 1) {
                add(point[i][j], i, 1, 0);
            } else {
                add(point[i][j], i, 1, 0);
                add(point[i][j], j, 1, 0);
            }
        }
    }
    std::pii ans = solve(s, t);
    printf("%d\n", n * (n - 1) * (n - 2) / 6 - ans.se);
    rep (i, 1, n + 1) {
        rep (j, 1, n + 1) {
            int u = point[i][j];
            if (!point[i][j]) continue;
            es (u, k, v) {
                if (v >= 1 && v <= n && !f[k]) {
                    assert(v == i || v == j);
                    if (v == i) res[i][j] = 1, res[j][i] = 0;
                    else res[i][j] = 0, res[j][i] = 1;
                }
            }
        }
    }
    rep (i, 1, n + 1) {
        rep (j, 1, n + 1) {
            printf("%d%c", res[i][j], " \n"[j == n]);
        }
    }
#ifdef LOCAL
    printf("%.10f\n", (db)clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/12487131.html
今日推荐