1426E.Rock, Paper, Scissors
Description
Analysis
题意概述
两个玩家共玩 n n n 场 ( 1 ≤ n ≤ 1 0 9 ) (1\le n\le10^9) (1≤n≤109)石头剪刀布,给出其分别出石头、剪刀、布的次数
求玩家 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 S→0,汇点 T → 7 T\to7 T→7
- 玩家 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;
}