码迷,mamicode.com
首页 > 其他好文 > 详细

2597: [Wc2007]剪刀石头布

时间:2019-01-30 23:17:13      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:printf   set   代码   http   个人   bool   比赛   typedef   cap   

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\n", 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;
}

 

2597: [Wc2007]剪刀石头布

标签:printf   set   代码   http   个人   bool   比赛   typedef   cap   

原文地址:https://www.cnblogs.com/mjtcn/p/10339984.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!