zoukankan      html  css  js  c++  java
  • 2597: [Wc2007]剪刀石头布

    2597: [Wc2007]剪刀石头布

    链接

    分析:  

      费用流。

      首先转化一下问题,整张图最优的情况是存在$C_n^3$个,即任意3个都行,然后考虑去掉最少不满足的三元环。

      如果u赢了v,u向v连一条边,如果v有k条入边,那么说明少了$C_k^2$个三元环,所对每场比赛分配度数,求最小费用最大流。

      具体地:S向每场比赛连容量为1,花费为0的边;每场比赛向两个人连容量为1,花费为0的边;每个人因为度数不同,花费不同,所以差分后建边。

      还有一种随机化+迭代的做法。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 20005, INF = 1e9;
    struct Edge { int from, to, nxt, cap, cost; } e[100005];
    int head[N], pre[N], dis[N], q[100005], deg[N], id[105][105], A[105][105], P[N], tag[N], En = 1, S, T;
    bool vis[N];
    
    inline void add_edge(int u,int v,int f,int w) {
        ++En; e[En].from = u, e[En].to = v, e[En].cap = f, e[En].cost = w, e[En].nxt = head[u]; head[u] = En;
        ++En; e[En].from = v, e[En].to = u, e[En].cap = 0, e[En].cost = -w, e[En].nxt = head[v]; head[v] = En;
    }
    bool spfa() {
        for (int i = 0; i <= T; ++i) dis[i] = INF, vis[i] = false, pre[i] = 0;
        int L = 1, R = 0;
        q[++R] = S, vis[S] = true, dis[S] = 0;
        while (L <= R) {
            int u = q[L ++]; vis[u] = false;
            for (int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if (dis[v] > dis[u] + e[i].cost && e[i].cap > 0) {
                    dis[v] = dis[u] + e[i].cost;
                    pre[v] = i;
                    if (!vis[v]) q[++R] = v, vis[v] = true;
                }
            }
        }
        return dis[T] != INF;
    }
    int mcf() {
        int Cost = 0, Flow = 0;
        while (spfa()) {
            int now = 1e9;
            for (int i = T; i != S; i = e[pre[i]].from) 
                now = min(now, e[pre[i]].cap);
            for (int i = T; i != S; i = e[pre[i]].from) 
                e[pre[i]].cap -= now, e[pre[i] ^ 1].cap += now;
            Cost += dis[T] * now;
            Flow += now;
        }
        return Cost;
    }
    int main() {
        freopen("a.in", "r", stdin);
        int n = read(), tot = n;
        if (n < 3) { printf("0"); return 0; }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= i; ++j) read();
            for (int j = i + 1; j <= n; ++j) {
                int x = read();
                id[i][j] = ++tot;
                if (x == 0) deg[j] ++, tag[tot] = 1;
                else if (x == 1) deg[i] ++, tag[tot] = 2;
                else { add_edge(tot, i, 1, 0); P[tot] = En; add_edge(tot, j, 1, 0); }
            }
        }
        S = 0, T = tot + 1;
        for (int i = n + 1; i <= tot; ++i) add_edge(S, i, 1, 0);
        for (int i = 1; i <= n; ++i) 
            for (int j = deg[i]; j < n - 1; ++j) add_edge(i, T, 1, j);
        int ans = n * (n - 1) * (n - 2) / 6;
        for (int i = 1; i <= n; ++i) 
            ans -= deg[i] * (deg[i] - 1) / 2;
        ans -= mcf();
        printf("%d
    ", ans);
        for (int i = 1; i <= n; ++i)
            for (int j = i + 1; j <= n; ++j) {
                if (tag[id[i][j]]) A[i][j] = tag[id[i][j]] - 1;
                else A[i][j] = e[P[id[i][j]]].cap ? 1 : 0;
            }
        for (int i = 1; i <= n; ++i, puts("")) {
            for (int j = 1; j < i; ++j) printf("%d ", A[j][i] ^ 1);
            for (int j = i; j <= n; ++j) printf("%d ", A[i][j]);
        }
        return 0;
    }
  • 相关阅读:
    设计模式 对象结构型 代理模式
    设计模式 对象/类结构型 适配器模式
    设计模式 创建型 原型模式
    设计模式 创建型 建造模式
    Django REST framework使用及源码分析之权限
    Django REST framework使用及源码分析之验证
    某游戏公司运维开发python笔试题
    django中间件的5个方法以及csrf的装饰器用法
    Django源码理解一
    消息中间件-RabbitMQ
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10339984.html
Copyright © 2011-2022 走看看