CF704D Captain America(上下界网络流)
题意:
二维平面给出\(n\)个点,现在可以给每个点进行染色,染红色的代价为\(r\),染蓝色的代价为\(b\)。
之后会有\(m\)个限制,形式如:\(t_i\ l_i\ d_i\),当\(t_i=1\)时,表示\(l_i\)行两种颜色的点数相差不超过\(d_i\);类似地,当\(t_i=2\)时表示的是列时的状态。
问最终怎么染色代价最小且符合限制条件。
思路:
- 带上下界的网络流。
- 我们不妨设\(r<b\),那么肯定是红点越多越好。我们找准最大这个数量关系,然后考虑最大流。
- 建图方式为:左右两排分别表示行和列,中间则为每个点,源点和左排相连带有上下界,汇点和右排相连带有上下界。
- 上下界很好推,假设第\(i\)行共\(tot_i\)个点,我们选\(x\)个红点,那么就有:\(|x-(tot - x)|\leq d\),绝对值打开化简即可得到\(x\)的范围,若一个满足范围,另一个点也必然满足范围。
- 为什么要在两排中间加上点?因为我们最后要输出方案,我们需要根据流过点的流量来判断这个点是否染色。
这种有源有汇最大流,首先转化为无源无汇最大流,得到\(s\)到\(t\)的可行流,最后去掉附加点和边,最后再从\(s\)到\(t\)跑一次最大流,两次的答案加起来即可得到答案。
注意进入流量若大于出度流量,我们连接源点向它来补充这多出来的。
详见代码:
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5e5 + 5;
#define INF 0x3f3f3f3f
int s, t, SS, TT;
int n, m, r, b, f;
void Fail() {
cout << -1 << '\n';
exit(0);
}
template <class T>
struct Dinic{
struct Edge{
int v, next;
T flow;
Edge(){}
Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {}
}e[N << 1];
int head[N], tot;
int dep[N], M[N];
int all;
void init() {
memset(head, -1, sizeof(head)); tot = 0;
}
void adde(int u, int v, T down, T up) {
if(up < down) Fail();
e[tot] = Edge(v, head[u], up - down);
head[u] = tot++;
e[tot] = Edge(u, head[v], 0);
head[v] = tot++;
M[u] -= down; M[v] += down;
}
void adde() {
for(int i = 0; i <= t; i++) {
if(M[i] > 0) adde(SS, i, 0, M[i]);
else if(M[i] < 0) adde(i, TT, 0, -M[i]);
}
adde(t, s, 0, INF);
}
bool BFS(int _S, int _T) {
memset(dep, 0, sizeof(dep));
queue <int> q; q.push(_S); dep[_S] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(!dep[v] && e[i].flow > 0) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[_T] != 0;
}
T dfs(int _S, int _T, T a) {
T flow = 0, f;
if(_S == _T || a == 0) return a;
for(int i = head[_S]; ~i; i = e[i].next) {
int v = e[i].v;
if(dep[v] != dep[_S] + 1) continue;
f = dfs(v, _T, min(a, e[i].flow));
if(f) {
e[i].flow -= f;
e[i ^ 1].flow += f;
flow += f;
a -= f;
if(a == 0) break;
}
}
if(!flow) dep[_S] = -1;
return flow;
}
T dinic(int _S, int _T) {
T max_flow = 0;
while(BFS(_S, _T)) max_flow += dfs(_S, _T, INF);
return max_flow;
}
T work() {
int tmp = dinic(SS, TT);
for(int i = head[SS]; i != -1; i = e[i].next) {
if(e[i].flow) Fail();
}
int ans = e[tot - 1].flow;
e[tot - 1].flow = e[tot - 2].flow = 0;
for(int i = head[SS]; i != -1; i = e[i].next) {
e[i].flow = e[i ^ 1].flow = 0;
}
for(int i = head[TT]; i != -1; i = e[i].next) {
e[i].flow = e[i ^ 1].flow = 0;
}
ans += dinic(s, t);
return ans;
}
//f = 1 -> r > b;
void Print(int f, int L, int R) {
for(int i = L + 1; i <= L + n; i++) {
bool flag = false;
for(int j = head[i]; j != -1; j = e[j].next) {
int v = e[j].v;
if(e[j].flow == 0 && v > n + L && v <= n + L + R) {
flag = true;
cout << (f == 1 ? 'b' : 'r');
}
}
if(!flag) cout << (f == 1 ? 'r' : 'b');
}
}
};
Dinic <int> solver;
int x[N], y[N], X[N], Y[N];
int mxx[N], mxy[N], cntx[N], cnty[N];
void Hash(int *a, int *b, int &c) {
sort(b + 1, b + n + 1);
c = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + c + 1, a[i]) - b;
}
void Hash(int &a, int &b) {
Hash(x, X, a); Hash(y, Y, b);
}
void run() {
cin >> r >> b;
if(r >= b) {
f = 1;
swap(r, b);
}
solver.init();
for(int i = 1; i <= n; i++) {
cin >> x[i] >> y[i];
X[i] = x[i], Y[i] = y[i];
}
int lx, ly;
Hash(lx, ly);
dbg(lx, ly);
s = 0, t = lx + ly + n + 1;
SS = t + 1, TT = t + 2;
for(int i = 1; i <= n; i++) {
solver.adde(x[i], lx + i, 0, 1);
solver.adde(lx + i, y[i] + n + lx, 0, 1);
}
for(int i = 1; i <= lx; i++) mxx[i] = n;
for(int i = 1; i <= ly; i++) mxy[i] = n;
for(int i = 1; i <= m; i++) {
int t, l, d; cin >> t >> l >> d;
if(t & 1) {
int p = lower_bound(X + 1, X + lx + 1, l) - X;
if(X[p] != l) continue;
else mxx[p] = min(mxx[p], d);
}
else {
int p = lower_bound(Y + 1, Y + ly + 1, l) - Y;
if(Y[p] != l) continue;
else mxy[p] = min(mxy[p], d);
}
}
for(int i = 1; i <= n; i++) ++cntx[x[i]];
for(int i = 1; i <= n; i++) ++cnty[y[i]];
for(int i = 1; i <= lx; i++) {
if(cntx[i] <= mxx[i]) solver.adde(s, i, 0, INF);
else solver.adde(s, i, (cntx[i] - mxx[i] + 1) / 2, (cntx[i] + mxx[i]) / 2);
}
for(int i = 1; i <= ly; i++) {
if(cnty[i] <= mxy[i]) solver.adde(n + lx + i, t, 0, INF);
else solver.adde(n + lx + i, t, (cnty[i] - mxy[i] + 1) / 2, (cnty[i] + mxy[i]) / 2);
}
solver.adde();
int flow = solver.work();
cout << 1ll * flow * r + 1ll * (n - flow) * b << '\n';
solver.Print(f, lx, ly);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
while(cin >> n >> m) run();
return 0;
}
CF704D Captain America(上下界网络流)的更多相关文章
- CF704D Captain America 上下界网络流
传送门 现在相当于说每一个条件都有一个染成红色的盾牌的数量限制\([l,r]\),需要满足所有限制且染成红色的盾牌数量最小/最大. 注意到一个盾牌染成红色对于一行和一列都会产生影响.如果选中一个物品对 ...
- CF#366 704D Captain America 上下界网络流
CF上的题,就不放链接了,打开太慢,直接上题面吧: 平面上有n个点, 第 i 个点的坐标为 ($X_i ,Y_i$), 你需要把每个点染成红色或者蓝色, 染成红色的花费为 r , 染成蓝色的花费为 b ...
- 【CF704D】Captain America(上下界网络流)
[CF704D]Captain America(上下界网络流) 题面 CF 洛谷 题解 如果没有限制,似乎就不用做了...因为我们只需要贪心的选择代价较小的颜色就行了. 那么我们不妨假设染红色的代价较 ...
- hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流推断 )
题意:有n个点和m条有向边构成的网络.每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏全部S到T的路径的费用和 > 毁坏全部T到 ...
- ACM-ICPC 2018 沈阳赛区网络预赛 F Fantastic Graph(贪心或有源汇上下界网络流)
https://nanti.jisuanke.com/t/31447 题意 一个二分图,左边N个点,右边M个点,中间K条边,问你是否可以删掉边使得所有点的度数在[L,R]之间 分析 最大流不太会.. ...
- 算法笔记--最大流和最小割 && 最小费用最大流 && 上下界网络流
最大流: 给定指定的一个有向图,其中有两个特殊的点源S(Sources)和汇T(Sinks),每条边有指定的容量(Capacity),求满足条件的从S到T的最大流(MaxFlow). 最小割: 割是网 ...
- POJ 2396 Budget(有源汇上下界网络流)
Description We are supposed to make a budget proposal for this multi-site competition. The budget pr ...
- HDU 4940 Destroy Transportation system(无源汇上下界网络流)
Problem Description Tom is a commander, his task is destroying his enemy’s transportation system. Le ...
- ACM-ICPC 2018 沈阳赛区网络预赛 F. Fantastic Graph (贪心或有源汇上下界网络流)
"Oh, There is a bipartite graph.""Make it Fantastic."X wants to check whether a ...
- [BZOJ2502]清理雪道 有上下界网络流(最小流)
2502: 清理雪道 Time Limit: 10 Sec Memory Limit: 128 MB Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场 ...
随机推荐
- JMeter面试题
1.Jmeter怎么录制脚本,怎么过滤,线程组有哪些内容? jmeter可以使用第三方的录制工具(badboy)或者使用jmeter自带的HTTP代理服务器录制脚本功能 jmeter录制原理:通过ht ...
- [C4] 前馈神经网络(Feedforward Neural Network)
前馈神经网络(Feedforward Neural Network - BP) 常见的前馈神经网络 感知器网络 感知器(又叫感知机)是最简单的前馈网络,它主要用于模式分类,也可用在基于模式分类的学习控 ...
- JDOJ3007 铺地板I
JDOJ3007 铺地板I https://neooj.com/oldoj/problem.php?id=3007 题目描述 有一个大小是 2 x N(1 <= N <= 105)的网格, ...
- DWR日志 在log4j.xml配置
一.日志 DWR依赖 Apache Commons Logging,可以使用log4j实现日志记录功能. 1.1 日志简介 和其他日志框架一样,当设置低等级的日志时所有高于此等级的日志也将会打印出来. ...
- 从零实现一个React:Luster(一):JSX解析器
前言 这是之前在掘金发的两条沸点,懒得写了,直接复制过来作为前言了.然后这个项目可能之后还会继续写,增加一些路由或者模板引擎的指令什么的,但是再过没多久寒假就有大块时间了就可能不摸这个鱼去开其它坑了, ...
- LocalDB 从2017更换到2014后一直显示连接不正确解决方案
问题描述:LocalDB 版本混装后出现默认实例创建不成功 无法连接到 (LocalDB)\MSSQLLocalDB. ------------------------------其他信息: 在与 S ...
- SqlServer 查看数据库、添加数据文件
一.查看SqlServer实例的数据库列表 1).直接在SSMS(SqlServer Management Studio)管理工具里面 展开实例下面的所有数据库便可查看 2).使用Transact- ...
- webform的原生操作图片预览和上传
1.使用input标签进行图片操作,input的标签有一个accept属性,accept 属性只能与 <input type="file"> 配合使用.它规定能够通过文 ...
- Delphi - DateTimePicker控件日期格式
设置成显示年.月.日.时.分.秒 1:将DateTimePicker的Format属性中加入日期格式设成 'yyyy-MM-dd HH:mm:ss',注意日期里月份对应的MM是大写,时间里的分钟对应的 ...
- 基于vue+springboot+docker网站搭建【九】负载均衡
后台mall-admin 负载均衡 1.新启动一个mall-admin docker实例 docker run -p 9002:9001 --name mall-admin-9002 --link m ...