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 最多能被分解成多少个数相乘就好了 ...
随机推荐
- C++ Primer Plus(一)
完整阅读C++ Primer Plus 系统重新学习C++语言部分,记录重要但易被忽略的,关键但易被遗忘的. 预备 1.C++相对于C增加了最关键的两项,面向对象和范型编程. 处理数据 2.对于变量明 ...
- Charles 安装证书后依旧抓取不到https请求的解决方案
1.打开charles——>help——>SSL proxying——>Install Charles Root Certificate 证书安装后,抓取https的包 2.查看Pr ...
- SpringCloud教程第6篇:config(F版本)
一.简介 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件.在Spring Cloud中,有分布式配置中心组件spring cloud config ...
- 黎活明8天快速掌握android视频教程--21_监听ContentProvider中数据的变化
采用ContentProvider除了可以让其他应用访问当前的app的数据之外,还有可以实现当app的数据发送变化的时候,通知注册了数据变化通知的调用者 其他所有的代码都和第20讲的一样,不同的地方看 ...
- TestNG离线安装步骤
1.下载testNG 离线安装包[eclipse-testng离线包],并解压.资源可以在下载:http://download.csdn.net/detail/u012100968/9623613: ...
- Typora及Markdown的介绍及使用
Typora及Markdown的介绍及使用 Typora是一款免费的Markdown编辑器,Typora不像其他Markdown编辑器一样使用一边代码一边预览的方式,而是写完代码之后直接出效果,所见即 ...
- Docker文件系统实战
关键词:Docker 联合文件系统 镜像 容器 云信私有化 在本文中,我们来实战构建一个Docker镜像,然后实例化容器,在Docker的生命周期中详细分析一下Docker的文件存储情况和Docker ...
- Write a program that prints its input one word per line.
#include <stdio.h> #define State '\n' void main() { int Juge=;/*only one space*/ int c=; while ...
- MyBatis执行流程的各阶段介绍
目录 一.mybatis极简示例 1.1 创建mybatis配置文件 1.2 创建数据库表 1.3 创建javabean 1.4 创建mapper映射文件 1.5 运行测试 二.mybatis的几大“ ...
- html中map area 热区自适应的原生js实现方案
在做自适应网页的时候,如果在图片中使用了热区map.图片可以通过样式实现:图片大小随页面变化,但是MAP中每个area的坐标并不能通过css直接实现自适应.这篇文章就介绍通过原生js来实现:MAP中每 ...