2020牛客暑期多校训练营(第一场)H Minimum-cost Flow
题目:给n个点,m条边。接下来m行包含(a,b,c),即a,b之间有单位流量代价为c的边。接下来有q个问题,每个问题给定(x,y),即假设每条边的容量为x/y时,从点1到点n流1单位的流量,最少的花费是多少,如果无法从点1到点n流1单位的流量则输出“NaN”。
思路:首先我们需要想到一个结论,每条边最多只能使用一次,这个自己比划一下就可以,其中包含贪心的想法。得到这个结论后,我们发现整张图就变成了流量为1的网络流。然后,根据(x,y)说明我们至少需要 y / x + (y % x != 0)条从1到n的最少花费路径,这个我们可以通过最小费用流预处理得到所有能够得到的最小花费路径,并记录每条路径的最小花费。这样,对于每个询问(x,y),我们只需要取前y / x小的边,如果y % x != 0,则从后面的边补充一些即可。
补充:为什么我们可以直接这样直接取路径,看上图,我们得到的最小花费应该是两个:3,21。这是懂得网络流算法都能看出的,如果我们有组询问(2,3),我们可以得到答案应该是ans = 3 * 2/3 + 21 * 1/3 = 9。但这两条路分别是1->2->3->4和1->3->2->4得到的,会感觉有点奇怪“这样就是答案”。其实我们需要回到网络流的反向边在算法中的用途"反流"和正向边可以把"反流"失去的流量再"补流",下面附一个来体现ans = 9是怎么得到的,然后思考。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring> using namespace std; #define ll long long
#define pb push_back
#define fi first
#define se second const int N = ;
const int M = ;
const int INF = 1e9 + 7e8;
struct edge
{
int to, nxt, cap, flow, w;
}e[M << ];
int head[N], d[N], vis[N], pre[N];
queue<int > que;
int a[N], b[N];
int n, m, tot, s, t, cnt; inline void add(int u, int v, int w)
{
e[tot].to = v; e[tot].w = w; e[tot].cap = ;
e[tot].flow = ; e[tot].nxt = head[u]; head[u] = tot++;
e[tot].to = u; e[tot].w = -w; e[tot].cap = ;
e[tot].flow = ; e[tot].nxt = head[v]; head[v] = tot++;
} bool spfa()
{
for(int i = ; i <= n; ++i) d[i] = INF, vis[i] = false, pre[i] = -;
while(!que.empty()) que.pop();
d[s] = ; vis[s] = true; pre[s] = -;
que.push(s);
//printf("s = %d t = %d\n", s, t);
while(!que.empty()){
int now = que.front();
que.pop();
vis[now] = false; for(int o = head[now]; ~o; o = e[o].nxt){
if(e[o].cap - e[o].flow && d[e[o].to] > d[now] + e[o].w){
d[e[o].to] = d[now] + e[o].w;
pre[e[o].to] = o;
if(!vis[e[o].to]){
vis[e[o].to] = true;
que.push(e[o].to);
}
}
}
}
if(pre[t] == -) return false;
else return true;
} void mcmf()
{
while(spfa()){
int _min = INF;
for(int o = pre[t]; ~o; o = pre[e[o ^ ].to]){
_min = min(_min, e[o].cap - e[o].flow);
}
for(int o = pre[t]; ~o; o = pre[e[o ^ ].to]){
e[o].flow += _min;
e[o ^ ].flow -= _min;
}
//cout << _min << endl;
//cout << "dis = " << d[t] << endl;
a[++cnt] = d[t];
//cout << "d = " << d[t] << endl;
}
for(int i = ; i <= cnt; ++i) a[i] += a[i - ];
} ll GCD(ll a, ll b)
{
return b == ? a : GCD(b, a % b);
} void solve()
{
while(~scanf("%d%d", &n, &m)){
cnt = ;
for(int i = ; i <= n; ++i) head[i] = -; tot = ;
int x, y, w;
for(int i = ; i <= m; ++i){
scanf("%d%d%d", &x, &y, &w);
add(x, y, w);
}
s = ; t = n;
mcmf(); int q;
scanf("%d", &q);
while(q--){
int x, y;
scanf("%d%d", &x, &y);
if(x == ){
puts("NaN");
continue;
}
int gcd = GCD(x, y);
y /= gcd; x /= gcd; int need = y / x + (y % x != );
if(need > cnt){
puts("NaN");
continue;
} need = y / x;
ll up = (ll)a[need] * x;
ll down = y;
int remains = y % x;
up += (ll)(a[need + ] - a[need]) * remains;
gcd = GCD(up, down);
up /= gcd; down /= gcd;
printf("%lld/%lld\n", up, down);
}
}
} int main(){ solve(); return ;
}
2020牛客暑期多校训练营(第一场)H Minimum-cost Flow的更多相关文章
- 2020牛客暑期多校训练营 第二场 K Keyboard Free 积分 期望 数学
LINK:Keyboard Free 我要是会正经的做法 就有鬼了. 我的数学水平没那么高. 三个同心圆 三个动点 求围成三角形面积的期望. 不会告辞. 其实可以\(n^2\)枚举角度然后算出面积 近 ...
- 2020牛客暑期多校训练营 第二场 J Just Shuffle 置换 群论
LINK:Just Shuffle 比较怂群论 因为没怎么学过 置换也是刚理解. 这道题是 已知一个置换\(A\)求一个置换P 两个置换的关键为\(P^k=A\) 且k是一个大质数. 做法是李指导教我 ...
- 2020牛客暑期多校训练营 第二场 I Interval 最大流 最小割 平面图对偶图转最短路
LINK:Interval 赛时连题目都没看. 观察n的范围不大不小 而且建图明显 考虑跑最大流最小割. 图有点稠密dinic不太行. 一个常见的trick就是对偶图转最短路. 建图有点复杂 不过建完 ...
- 2020牛客暑期多校训练营 第二场 C Cover the Tree 构造 贪心
LINK:Cover the Tree 最受挫的是这道题,以为很简单 当时什么都想不清楚. 先胡了一个树的直径乱搞的贪心 一直过不去.后来意识到这类似于最经典长链剖分优化贪心的做法 然后那个是求最大值 ...
- 2020牛客暑期多校训练营 第二场 B Boundary 计算几何 圆 已知三点求圆心
LINK:Boundary 计算几何确实是弱项 因为好多东西都不太会求 没有到很精通的地步. 做法很多,先说官方题解 其实就是枚举一个点 P 然后可以发现 再枚举一个点 然后再判断有多少个点在圆上显然 ...
- 2020牛客暑期多校训练营 第二场 A All with Pairs 字符串hash KMP
LINK:All with Pairs 那天下午打这个东西的时候状态极差 推这个东西都推了1个多小时 (比赛是中午考试的我很困 没睡觉直接开肝果然不爽 一开始看错匹配的位置了 以为是\(1-l\)和\ ...
- 2020牛客暑假多校训练营 第二场 H Happy Triangle set 线段树 分类讨论
LINK:Happy Triangle 这道题很容易. 容易想到 a+b<x a<x<b x<a<b 其中等于的情况在第一个和第三个之中判一下即可. 前面两个容易想到se ...
- 2020牛客暑期多校训练营(第一场)Easy Integration
传送门:J. Easy Integration 题意:给你n,求这个积分,最后的结果分子是记为p,分母记为q. 求(p*q-1)mod 998244353. 题解:比赛完看到巨巨说这是贝塔函数,我一搜 ...
- 2020牛客暑期多校训练营(第四场)BCFH
BCFH B. Basic God Problem 题意 给出c和n,求fc(n). 题解 递归到最后 fc 函数肯定等于1,那么就变成了求c被乘了几次,只要找到 x 最多能被分解成多少个数相乘就好了 ...
随机推荐
- control+Z的逆 control+Y
接触过电脑的朋友一定知道control键加Z可以在大多时候撤销我们前一步的操作,相当于计算机系统里最“广谱”的后悔药. 然而,你有没有在编辑文本的时候却因为撤销的操作而后悔?输入文本之后撤销,发现少了 ...
- Java将日期转化为大写格式(阿拉伯大写数字)
效果: 代码部分: public static void main(String[] args) { SimpleDateFormat sdf=new SimpleDateFormat("y ...
- Spring中的AOP(二)
2.5 Spring的织入 在上一篇文章中,我们介绍了Pointcut.Advice.Advisor三个必要模块,剩下的工作就是把它们拼装起来,也就是织入过程.在Spring中,使用类org.spri ...
- Java WebService(实战) 简单实例
一.准备工作(以下为本实例使用工具) 1.MyEclipse10.7.1 2.JDK 1.6.0_22 二.创建服务端 1.创建[Web Service Project],命名为[TheService ...
- Python学习之准备工作
Python学习之准备工作 编程语言历史 在计算机硬件基础中我们大概介绍了一下计算机的发展历史.了解到在曾经有一段时期里计算机是不存在操作系统这一概念的,所有需要计算机完成的操作都需要当时的程序员来与 ...
- python脚本中调用其他脚本
如果只关注脚本中调用他脚本直接看代码30行 PS:该脚本功能有:自动清理目录,创建目录,自动运行脚本,以此提升工作效率 import numpy as np import os from shutil ...
- sql 语句和实例
修改字段格式的sql语句: alter table tablename alter column colname newDataType 比如:alter table mytable alter co ...
- java使字符串的数字加一
/** * 字符串+1方法,该方法将其结尾的整数+1,适用于任何以整数结尾的字符串,不限格式,不限分隔符. * @author zxcvbnmzb * @param testStr 要+1的字符串 * ...
- SQL Server 索引的含义和特点
索引用于快速找出在某个列中某一特定值的行.不使索引,数据库必须从第一条记录开始读完整个表,直到找到相关行.如果表中查询的列有一个索引,数据库能快速到达一个位置去搜寻数据,而不必查看所有数据. 索引的含 ...
- css怎么样设置透明度?
css怎么样设置透明度?下面本篇文章就来给大家介绍一下使用css设置透明度的方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 在CSS中想要设置透明度,可以使用opacity属性 ...