1426E

1426E.Rock, Paper, Scissors

Description

在这里插入图片描述

Analysis

题意概述

两个玩家共玩 n n n ( 1 ≤ n ≤ 1 0 9 ) (1\le n\le10^9) (1n109)石头剪刀布,给出其分别出石头、剪刀、布的次数

求玩家 1 1 1 最少或最多可能的获胜次数

分析(基于 M C M F MCMF MCMF 的解法)

看到 f l o w flow flow 的标签就直接上网络流了,简单琢磨了一下建图方式,没有标签以作者目前的实力可能无法 a c ac ac

最小费用最大流 a n d and and 最大费用最大流(分别对应最少获胜次数和最多获胜次数)

建图分析

  • 源点 S → 0 S\to0 S0,汇点 T → 7 T\to7 T7
  • 玩家 1 1 1 a 1 , a 2 , a 3 → a_1,a_2,a_3\to a1,a2,a3 剪刀、石头、布 → \to 节点 1 , 2 , 3 1,2,3 1,2,3
  • 玩家 2 2 2 b 1 , b 2 , b 3 → b_1,b_2,b_3\to b1,b2,b3 剪刀、石头、布 → \to 节点 4 , 5 , 6 4,5,6 4,5,6

S S S 向玩家 1 1 1 的对应节点连接一条容量为 a i a_i ai,费用为 0 0 0 的边

玩家 2 2 2 的对应节点向 T T T 连接一条容量为 b i b_i bi,费用为 0 0 0 的边

玩家 1 1 1 的对应节点向玩家 2 2 2 的对应节点连接一条容量为 ∞ \infin 的边,费用:平局/负: 0 0 0,胜利: 1 1 1

原网络的每一个可行流,对应一场合法的游戏,总费用即为玩家 1 1 1 的胜利次数

以此,求最小费用最大流 a n d and and 最大费用最大流即可

Code

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

constexpr const int N = 10, M = 40, inf = 0x3f3f3f3f;

int h[N], e[M], ne[M], w[M], f[M], idx;
int dist[N], d[N], pre[N], q[N], hh, tt;
bool st[N];
int n, S, T, x, flow, cost;

void add(int a, int b, int c, int d)
{
    e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx++;
    e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx++;
}
bool spfa()
{
    memset(d, 0, sizeof d);
    memset(dist, 0x3f, sizeof dist);
    hh = 0, tt = 1;
    q[0] = S, d[S] = inf, dist[S] = 0;
    
    while(hh != tt){
        int u = q[hh++];
        if(hh == N) hh = 0;
        st[u] = 0;
        
        for(int i = h[u]; ~i; i = ne[i]){
            int j = e[i];
            if(f[i] && dist[j] > dist[u] + w[i]){
                dist[j] = dist[u] + w[i];
                d[j] = min(d[u], f[i]);
                pre[j] = i;
                if(!st[j]){
                    st[j] = 1;
                    q[tt++] = j;
                    if(tt == N) tt = 0;
                }
            }
        }
    }
    
    return d[T] > 0;
}

void EK(int& flow, int& cost)
{
    flow = cost = 0;
    while(spfa())
    {
        flow += d[T], cost += dist[T] * d[T];
        for(int i = T; i != S; i = e[pre[i] ^ 1])
            f[pre[i]] -= d[T], f[pre[i] ^ 1] += d[T];
    }
}

int main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    cin >> n;

    memset(h, -1, sizeof h);

    S = 0, T = 7;

    for(int i = 1; i <= 3; i++)
    {
        cin >> x;
        add(S, i, x, 0);
        add(i, i + 3, inf, 0);
    }

    for(int i = 1; i <= 3; i++)
    {
        cin >> x;
        add(i + 3, T, x, 0);
    }

    add(1, 5, inf, 1);
    add(1, 6, inf, 0);
    add(2, 4, inf, 0);
    add(2, 6, inf, 1);
    add(3, 4, inf, 1);
    add(3, 5, inf, 0);

    EK(flow, cost);

    cout << cost << " ";

    for(int i = 0; i < idx; i += 2)
    {
        f[i] += f[i ^ 1], f[i ^ 1] = 0;
        w[i] = -w[i], w[i ^ 1] = -w[i ^ 1];
    }
    
    EK(flow, cost);
    
    cout << -cost << '\n';

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值