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的更多相关文章

  1. 2020牛客暑期多校训练营 第二场 K Keyboard Free 积分 期望 数学

    LINK:Keyboard Free 我要是会正经的做法 就有鬼了. 我的数学水平没那么高. 三个同心圆 三个动点 求围成三角形面积的期望. 不会告辞. 其实可以\(n^2\)枚举角度然后算出面积 近 ...

  2. 2020牛客暑期多校训练营 第二场 J Just Shuffle 置换 群论

    LINK:Just Shuffle 比较怂群论 因为没怎么学过 置换也是刚理解. 这道题是 已知一个置换\(A\)求一个置换P 两个置换的关键为\(P^k=A\) 且k是一个大质数. 做法是李指导教我 ...

  3. 2020牛客暑期多校训练营 第二场 I Interval 最大流 最小割 平面图对偶图转最短路

    LINK:Interval 赛时连题目都没看. 观察n的范围不大不小 而且建图明显 考虑跑最大流最小割. 图有点稠密dinic不太行. 一个常见的trick就是对偶图转最短路. 建图有点复杂 不过建完 ...

  4. 2020牛客暑期多校训练营 第二场 C Cover the Tree 构造 贪心

    LINK:Cover the Tree 最受挫的是这道题,以为很简单 当时什么都想不清楚. 先胡了一个树的直径乱搞的贪心 一直过不去.后来意识到这类似于最经典长链剖分优化贪心的做法 然后那个是求最大值 ...

  5. 2020牛客暑期多校训练营 第二场 B Boundary 计算几何 圆 已知三点求圆心

    LINK:Boundary 计算几何确实是弱项 因为好多东西都不太会求 没有到很精通的地步. 做法很多,先说官方题解 其实就是枚举一个点 P 然后可以发现 再枚举一个点 然后再判断有多少个点在圆上显然 ...

  6. 2020牛客暑期多校训练营 第二场 A All with Pairs 字符串hash KMP

    LINK:All with Pairs 那天下午打这个东西的时候状态极差 推这个东西都推了1个多小时 (比赛是中午考试的我很困 没睡觉直接开肝果然不爽 一开始看错匹配的位置了 以为是\(1-l\)和\ ...

  7. 2020牛客暑假多校训练营 第二场 H Happy Triangle set 线段树 分类讨论

    LINK:Happy Triangle 这道题很容易. 容易想到 a+b<x a<x<b x<a<b 其中等于的情况在第一个和第三个之中判一下即可. 前面两个容易想到se ...

  8. 2020牛客暑期多校训练营(第一场)Easy Integration

    传送门:J. Easy Integration 题意:给你n,求这个积分,最后的结果分子是记为p,分母记为q. 求(p*q-1)mod 998244353. 题解:比赛完看到巨巨说这是贝塔函数,我一搜 ...

  9. 2020牛客暑期多校训练营(第四场)BCFH

    BCFH B. Basic God Problem 题意 给出c和n,求fc(n). 题解 递归到最后 fc 函数肯定等于1,那么就变成了求c被乘了几次,只要找到 x 最多能被分解成多少个数相乘就好了 ...

随机推荐

  1. 2019-02-09 python爬取mooc视频项目初级简单版

    今天花了一下午时间来做这东西,之前没有自己写过代码,50几行的代码还是查了很多东西啊,果然学起来和自己动起手来完全是两码事. 方案:requests库+正则表达式提取视频下载链接+urlretriev ...

  2. 附016.Kubernetes_v1.17.4高可用部署

    一 kubeadm介绍 1.1 概述 参考<附003.Kubeadm部署Kubernetes>. 1.2 kubeadm功能 参考<附003.Kubeadm部署Kubernetes& ...

  3. Java++:安全|API接口安全性设计

    接口的安全性主要围绕 token.timestamp 和 sign 三个机制展开设计,保证接口的数据不会被篡改和重复调用,下面具体来看: Token授权机制: 用户使用用户名密码登录后服务器给客户端返 ...

  4. 手把手教你使用Python生成图灵智能小伙伴,实现工作助手/闲聊功能

    /1 前言/ 在家闲着,做个小项目,基于Python,实现一个语聊小机器人,分享给大家.项目整体比较简单,官方文档介绍的非常详细,可快速上手. /2 目标/ 将图灵机器人放到桌面,实现工作助手/陪聊功 ...

  5. 内存节省机制C演示

    编写代码实质是通过指令对计算机内存进行操作,计算机的硬件设备往往十分有限,尤其是内存.如何使有限的存储空间利用效率达到最大,成为了代码优化首先要考虑的事情. 比如,输入三个数比较大小并输出最小值.下面 ...

  6. robot framework使用小结(三)

    robot framework采用行为驱动 新建测试案例baidu04,添加Library:Selenium2Library 右键项目名robotProject-->New Resource-- ...

  7. PHP输入流

    PHP输入流php://input,对于这个的官方解释是: php://input可以读取没有处理过的POST数据.相较于$HTTP_RAW_POST_DATA而言,它给内存带来的压力较小,并且不需要 ...

  8. 比Minikube更快,使用Kind快速创建K8S学习环境

    简述 K8S 如火如荼的发展着,越来越多人想学习和了解 K8S,但是由于 K8S 的入门曲线较高很多人望而却步. 然而随着 K8S 生态的蓬勃发展,社区也呈现了越来越多的部署方案,光针对生产可用的环境 ...

  9. MySQL 百万级数据量分页查询方法及其优化

    方法1: 直接使用数据库提供的SQL语句 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N 适应场景: 适用于数据量较少的情况(元组百/千级) 原因/缺 ...

  10. 11. RobotFramework内置库-Collections

    Collections库是RobotFramework用来处理列表和字典的库,详细可参见官方介绍. 官方地址:http://robotframework.org/robotframework/late ...