题目传送门

  传送门

题目大意

  给定一个费用流,每条边有一个初始流量$c_i$和单位流量费用$d_i$,增加一条边的1单位的流量需要花费$b_i$的代价而减少一条边的1单位的流量需要花费$a_i$的代价。要求最小化总费用减少量和调整次数的比值(至少调整一次)。

  根据基本套路,二分答案,移项,可以得到每条边的贡献。

  设第$i$条边的流量变化量为$m_i$,每次变化花费的平均费用为$w_i$。那么有

$\sum c_id_i - \sum (c_i + m_i)d_i + |m_i|(w_i + mid) > 0$

$\sum m_id_i+ |m_i|(w_i + mid) < 0$

  那么二分答案后等于判断是否存在一个增广环的费用和为负。(请手动参见式子脑补边权)。

  然后可以写个spfa。

Code

 /**
* bzoj
* Problem#3597
* Accepted
* Time: 464ms
* Memory: 1720k
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
typedef bool boolean; template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} typedef class Edge {
public:
int ed, nx;
double w; Edge(int ed, int nx, double w) : ed(ed), nx(nx), w(w) { }
} Edge; typedef class MapManager {
public:
int* h;
vector<Edge> es; MapManager() { }
MapManager(int n) {
h = new int[(n + )];
pfill(h, h + n + , -);
}
~MapManager() {
delete[] h;
es.clear();
} void addEdge(int u, int v, double w) {
es.push_back(Edge(v, h[u], w));
h[u] = (signed) es.size() - ;
} Edge& operator [] (int p) {
return es[p];
}
} MapManager; const double dinf = 1e10;
const double eps = 1e-; typedef class Graph {
public:
int n, s;
MapManager g; int *cnt;
double *f;
boolean *vis; Graph(int n, int s) : n(n), s(s), g(n) {
cnt = new int[(n + )];
f = new double[(n + )];
vis = new boolean[(n + )];
pfill(vis, vis + n + , false);
} boolean neg_circle() {
static queue<int> que;
pfill(f, f + n + , dinf);
pfill(cnt, cnt + n + , );
f[s] = , cnt[s]++;
que.push(s);
while (!que.empty()) {
int e = que.front();
que.pop();
vis[e] = false;
for (int i = g.h[e], eu; ~i; i = g[i].nx) {
eu = g[i].ed;
double w = f[e] + g[i].w;
if (w < f[eu]) {
f[eu] = w, cnt[eu]++;
if (cnt[eu] > n)
return true;
if (!vis[eu]) {
que.push(eu);
vis[eu] = true;
}
}
}
}
return false;
}
} Graph; int n, m;
int *u, *v, *a, *b, *c, *d;
double init_ans = 0.0; inline void init() {
scanf("%d%d", &n, &m);
u = new int[(m + )];
v = new int[(m + )];
a = new int[(m + )];
b = new int[(m + )];
c = new int[(m + )];
d = new int[(m + )];
for (int i = ; i <= m; i++) {
scanf("%d%d%d%d%d%d", u + i, v + i, a + i, b + i, c + i, d + i);
init_ans += c[i] * d[i];
}
} boolean check(double mid) {
Graph graph(n + , n + );
MapManager& g = graph.g; for (int i = ; i <= m; i++) {
if (u[i] == n + ) {
g.addEdge(u[i], v[i], );
} else if (c[i]) {
g.addEdge(u[i], v[i], d[i] + b[i] + mid);
g.addEdge(v[i], u[i], -d[i] + a[i] + mid);
} else {
g.addEdge(u[i], v[i], d[i] + b[i] + mid);
}
} return graph.neg_circle();
} inline void solve() {
double l = , r = init_ans, mid;
for (int t = ; t < && l < r - eps; t++) {
mid = (l + r) / ;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.2lf\n", l);
} int main() {
init();
solve();
return ;
}

spfa

  然后再讲讲费用流做法。因为不存在负的流量,但是我们知道$c_i' \geqslant 0$,因此我们考虑将$m_i$变成$-c_i + m_i'$。

  其中$m_i'$始终非负。可以理解为这个做法就是将所有边的流量先变为0再重新调整。

  对于绝对值的部分稍微处理一下就行了。(之前那个式子脑残取了等,调了半天,sad。。。)

Code

 /**
* bzoj
* Problem#3597
* Accepted
* Time: 1168ms
* Memory: 2004k
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
typedef bool boolean; template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} typedef class Edge {
public:
int ed, nx, r;
double c; Edge(int ed = , int nx = , int r = , double c = ) : ed(ed), nx(nx), r(r), c(c) { }
} Edge; typedef class MapManager {
public:
int* h;
vector<Edge> es; MapManager() { }
MapManager(int n) {
h = new int[(n + )];
pfill(h, h + n + , -);
}
~MapManager() {
delete[] h;
es.clear();
} void addEdge(int u, int v, int r, double c) {
es.push_back(Edge(v, h[u], r, c));
h[u] = (signed) es.size() - ;
} void addArc(int u, int v, int cap, double c) {
addEdge(u, v, cap, c);
addEdge(v, u, , -c);
} Edge& operator [] (int p) {
return es[p];
}
} MapManager; const signed int inf = (signed) (~0u >> );
const double dinf = 1e10;
const double eps = 1e-; template <typename T>
T __abs(T x) {
return (x < ) ? (-x) : (x);
} typedef class Network {
public:
int S, T;
MapManager g; int *le;
int *mf;
double *f;
boolean *vis; Network() { }
// be sure T is the last node
Network(int S, int T) : S(S), T(T), g(T) {
f = new double[(T + )];
le = new int[(T + )];
mf = new int[(T + )];
vis = new boolean[(T + )];
pfill(vis, vis + T, false);
}
~Network() {
delete[] f;
delete[] le;
delete[] mf;
delete[] vis;
} double spfa() {
double w;
static queue<int> que;
pfill(f, f + T + , dinf);
que.push(S);
f[S] = , le[S] = -, mf[S] = inf;
while (!que.empty()) {
int e = que.front();
que.pop();
vis[e] = false;
for (int i = g.h[e], eu; ~i; i = g[i].nx) {
if (!g[i].r)
continue;
eu = g[i].ed, w = f[e] + g[i].c;
if (w < f[eu]) {
f[eu] = w, le[eu] = i, mf[eu] = min(mf[e], g[i].r);
if (!vis[eu]) {
vis[eu] = true;
que.push(eu);
}
}
}
}
if (__abs(f[T] - dinf) < eps)
return dinf;
double rt = ;
for (int p = T, e; ~le[p]; p = g[e ^ ].ed) {
e = le[p];
g[e].r -= mf[T];
g[e ^ ].r += mf[T];
rt += mf[T] * g[e].c;
}
return rt;
} double min_cost() {
double rt = , delta;
while (__abs((delta = spfa()) - dinf) >= eps) {
rt += delta;
}
return rt;
}
} Network; // S: n + 1, T: n + 2
int n, m;
int *u, *v, *a, *b, *c, *d;
double init_ans = 0.0; inline void init() {
scanf("%d%d", &n, &m);
u = new int[(m + )];
v = new int[(m + )];
a = new int[(m + )];
b = new int[(m + )];
c = new int[(m + )];
d = new int[(m + )];
for (int i = ; i <= m; i++) {
scanf("%d%d%d%d%d%d", u + i, v + i, a + i, b + i, c + i, d + i);
init_ans += c[i] * d[i];
}
} boolean check(double mid) {
double cost = ;
Network network(n + , n + );
MapManager& g = network.g;
for (int i = ; i <= m; i++) {
if (u[i] == n + ) {
g.addArc(u[i], v[i], c[i], );
} else {
g.addArc(u[i], v[i], c[i], -(a[i] + mid) + d[i]);
g.addArc(u[i], v[i], inf, b[i] + mid + d[i]);
// cost += c[i] * (-d[i] + a[i] + mid);
cost += c[i] * (-d[i] + a[i] + mid);
}
}
cost += network.min_cost();
return cost < ;
} inline void solve() {
double l = , r = init_ans, mid;
for (int t = ; t < && l < r - eps; t++) {
mid = (l + r) / ;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.2lf\n", l);
} int main() {
init();
solve();
return ;
}

bzoj 3597 [Scoi2014] 方伯伯运椰子 - 费用流 - 二分答案的更多相关文章

  1. bzoj 3597: [Scoi2014]方伯伯运椰子 0/1分数规划

    3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 144  Solved: 78[Submit][Status ...

  2. bzoj 3597: [Scoi2014]方伯伯运椰子 [01分数规划 消圈定理 spfa负环]

    3597: [Scoi2014]方伯伯运椰子 题意: from mhy12345 给你一个满流网络,对于每一条边,压缩容量1 需要费用ai,扩展容量1 需要bi, 当前容量上限ci,每单位通过该边花费 ...

  3. bzoj 3597: [Scoi2014]方伯伯运椰子

    Description Input 第一行包含二个整数N,M 接下来M行代表M条边,表示这个交通网络 每行六个整数,表示Ui,Vi,Ai,Bi,Ci,Di 接下来一行包含一条边,表示连接起点的边 Ou ...

  4. 3597: [Scoi2014]方伯伯运椰子[分数规划]

    3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 404  Solved: 249 [Submit][Sta ...

  5. BZOJ 3597 SCOI2014 方伯伯送椰子 网络流分析+SPFA

    原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3597 Description 四川的方伯伯为了致富,决定引进海南的椰子树.方伯伯的椰子园十 ...

  6. bzoj3597[Scoi2014]方伯伯运椰子 01分数规划+spfa判负环

    3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 594  Solved: 360[Submit][Statu ...

  7. BZOJ3597 SCOI2014方伯伯运椰子(分数规划+spfa)

    即在总流量不变的情况下调整每条边的流量.显然先二分答案变为求最小费用.容易想到直接流量清空跑费用流,但复杂度略有些高. 首先需要知道(不知道也行?)一种平时基本不用的求最小费用流的算法——消圈法.算法 ...

  8. Bzoj3597: [Scoi2014]方伯伯运椰子

    题面 传送门 Sol 消圈定理:如果一个费用流网络的残量网络有负环,那么这个费用流不优 于是这个题就可以建出残量网络,然后分数规划跑负环了 # include <bits/stdc++.h> ...

  9. [SCOI2014]方伯伯运椰子

    嘟嘟嘟 01分数规划思维题. 题中要求交通总量不减少,那么如果总量增加的话,总费用就会增加,所以一定不是更优的解.那么总量守恒. 这是不是就想到了网络流?对于每一个节点流入量等于流出量.然后就是很有思 ...

随机推荐

  1. 软件分享--EditPlus

    有些人分享的报毒,不好用,所以在这分享个好用的.百度网盘地址: 链接: https://pan.baidu.com/s/15s7I6p0K_36KPtzRDbHfrw 密码:kl5w

  2. laradock

    配置xdebug:http://m.php.cn/article/407434.html

  3. Building gRPC Client iOS Swift Note Taking App

    gRPC is an universal remote procedure call framework developed by Google that has been gaining inter ...

  4. CF1033G Chip Game

    题意 给你一个长度为\(n\)的序列和一个数\(m\). 小A和小B分别在\([1,m]\)选出一个数\(a\)和\(b\),然后开始游戏. 轮到小A时,他选择一个元素减\(a\):小B则选择一个元素 ...

  5. win10下配置默认软件(转)

    add by zhj: 以配置默认浏览器为例说明,配置其它程序类似 原文:https://blog.csdn.net/u013246898/article/details/52032567 第一步:在 ...

  6. pymysql连接数据库报错:'NoneType' object has no attribute 'encoding'

    直接写 utf8 即可.

  7. LAYUI layedit 富文本框内容的取值

    js 1.第一种方法 2.第二种方法

  8. FEX(Fabric Extender)

    一.FEX Cisco Nexus 2000 FEX作为N5K.N6K.N7K.FI的一个远程线卡,单独的2K是没有网管功能的,必须配合父系交换机使用. 主要解决TOR和EOR的问题,TOR,接线简单 ...

  9. what's the 灰盒测试

    what's the 灰盒测试 灰盒测试的概念:是一种综合测试的方法,他将白盒测试和黑盒测试结合在一起,构成一种无缝测试技术. 灰盒测试的思想:是基于程序运行时的外部表现又结合程序内部逻辑结构来设计测 ...

  10. .Net新利器Rider的破解安装与使用

    准备 介绍 Rider 是 JetBrains 提供的一款用于 .Net 开发的 IDE,相对于 VS,它显得更加轻量(才 500m 左右),并且不管是提示功能还是流畅度都不逊色于 VS 且某方面可能 ...