题目大意

给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若

干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。

如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。

题解

首先我们很容易用一个\(\Theta (n^2)\)的算法求出对于每个元素的lis。

考虑以下的建图方式:

由S向f[i]==1的点连边,容量为\(\infty\),

由f[i] = max 向 T 连边, 容量为\(\infty\),

对于每个点,拆为两个点,费用就是B[i]。

为什么这样建图是对的?原因很简单,原问题等价于在新图中找一个点集,使得s到t不再连通,这让我们联想到最小割,考虑到s,t到每个点不计入费用,所以我们设为\(\infty\)。

那么第一个问题解决了,关键是第二个问题:怎样找出字典序最小的割?

我们这样考虑:既然是字典序最小,我们把C[i]从小到大排序,依次检查每一条边,如果在剩余网络中它不连通,那么这条边一定是原图的一个最小割,我们把这条边删除,同时从汇点开始退流。具体的,我们可以从汇点向v跑一次最大流,u向原点跑一次最大流,这样一定会退回一些流,使得这条边的影响消失。

这样我们就解决了这个问题,详细过程见(我写了4个小时的)代码。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000;
int A[maxn], B[maxn], C[maxn], f[maxn];
int n, s, t, v;
const int inf = 1000000010;
struct edge {
int from;
int to;
int cap;
};
struct haha {
int id;
int Ci;
} cc[maxn]; inline int read() {
char c = getchar();
int f = 1, x = 0;
while (!isdigit(c)) {
if (c == '-')
f = -1;
c = getchar();
}
while (isdigit(c))
x = x * 10 + c - '0', c = getchar();
return x * f;
} bool cmp(haha a, haha b) { return a.Ci < b.Ci; } vector<edge> edges;
vector<int> G[maxn];
inline void add_edge(int from, int to, int cap) {
edges.push_back((edge){from, to, cap});
edges.push_back((edge){to, from, 0});
int m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
inline void reaad() {
scanf("%d", &n);
s = 0, t = 2 * n + 1, v = t + 1;
for (int i = 1; i <= n; i++) {
A[i] = read();
}
for (int i = 0; i < v; i++)
G[i].clear();
edges.clear();
for (int i = 1; i <= n; i++)
B[i] = read();
for (int i = 1; i <= n; i++) {
C[i] = read();
cc[i].id = i;
cc[i].Ci = C[i];
}
for (int i = 1; i <= n; i++)
add_edge(i, i + n, B[i]);
for (int i = 1; i <= n; i++)
f[i] = 1;
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (A[j] < A[i])
f[i] = max(f[i], f[j] + 1);
} ans = max(ans, f[i]);
}
for (int i = 1; i <= n; i++) {
if (ans == f[i]) {
add_edge(i + n, t, inf);
}
if (f[i] == 1)
add_edge(s, i, inf);
for (int j = 1; j <= n; j++) {
if (A[j] < A[i] && j < i && f[i] == f[j] + 1)
add_edge(j + n, i, inf);
}
}
}
int dist[maxn], iter[maxn];
inline void bfs(int s) {
memset(dist, -1, sizeof(dist));
dist[s] = 0;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < G[u].size(); i++) {
edge &e = edges[G[u][i]];
if (e.cap > 0 && dist[e.to] == -1) {
dist[e.to] = dist[u] + 1;
q.push(e.to);
}
}
}
}
inline int dfs(int s, int t, int flow) {
if (s == t)
return flow;
for (int &i = iter[s]; i < G[s].size(); i++) {
edge &e = edges[G[s][i]];
if (e.cap > 0 && dist[e.to] > dist[s]) {
int d = dfs(e.to, t, min(e.cap, flow));
if (d > 0) {
e.cap -= d;
edges[G[s][i] ^ 1].cap += d;
return d;
}
}
}
return 0;
}
inline int dinic(int s, int t) {
int flow = 0;
while (1) {
bfs(s);
if (dist[t] == -1)
return flow;
memset(iter, 0, sizeof(iter));
int d;
while (d = dfs(s, t, inf))
flow += d;
}
return flow;
}
int main() {
// freopen("input", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
reaad();
int ans = dinic(s, t);
int tot = 0;
int rec[maxn];
memset(rec, 0, sizeof(rec));
sort(cc + 1, cc + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
int now = cc[i].id;
int u = now, v = now + n;
bfs(u);
if (dist[v] != -1)
continue;
rec[tot++] = now;
dinic(t, v);
dinic(u, s);
edges[(now - 1) * 2].cap = edges[(now - 1) * 2 + 1].cap = 0;
}
sort(rec, rec + tot);
printf("%d %d\n", ans, tot);
for (int i = 0; i < tot-1; i++) {
printf("%d ", rec[i]);
}
printf("%d\n", rec[tot-1]);
}
return 0;
}

[bzoj3532][Sdoi2014]Lis——拆点最小割+字典序+退流的更多相关文章

  1. BZOJ.3532.[SDOI2014]LIS(最小割ISAP 退流)

    BZOJ 洛谷 \(LIS\)..经典模型? 令\(f_i\)表示以\(i\)结尾的\(LIS\)长度. 如果\(f_i=1\),连边\((S,i,INF)\):如果\(f_i=\max\limits ...

  2. bzoj千题计划141:bzoj3532: [Sdoi2014]Lis

    http://www.lydsy.com/JudgeOnline/problem.php?id=3532 如果没有字典序的限制,那么DP拆点最小割即可 加上字典序的限制: 按c从小到大枚举最小割边集中 ...

  3. P1345 [USACO5.4]奶牛的电信[拆点+最小割]

    题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相 ...

  4. UVA1660 电视网络 Cable TV Network[拆点+最小割]

    题意翻译 题目大意: 给定一个n(n <= 50)个点的无向图,求它的点联通度.即最少删除多少个点,使得图不连通. 解析 网络瘤拆点最小割. 定理 最大流\(=\)最小割 感性地理解(口胡)一下 ...

  5. 【Luogu】P2057善意的投票(最小割转最大流)

    题目链接 也算水题一道吧,不过Round1感性理解一下就xjb建了个图,40 Round2仔细分析了一会,理性建了个图,90 然后分析了半天……改大数组就A了…… 从S到所有值为1的点连一条inf的边 ...

  6. ACM/ICPC 之 伞兵-最小割转最大流(POJ3308)

    //以行列建点,伞兵位置为单向边-利用对数将乘积转加法 //最小割转最大流 //Time:63Ms Memory:792K #include<iostream> #include<c ...

  7. BZOJ3532 : [Sdoi2014]Lis

    f[i]表示以i为结尾的LIS长度 对于所有f[i]=1的,由S向i连边 对于所有f[i]=maxf的,由i向T连边 对于j<i,a[j]<a[i],且f[j]+1=f[i]的,j向i连边 ...

  8. POJ 1815 Friendship(最小割+字典序输出割点)

    http://poj.org/problem?id=1815 题意: 在现代社会,每个人都有自己的朋友.由于每个人都很忙,他们只通过电话联系.你可以假定A可以和B保持联系,当且仅当:①A知道B的电话号 ...

  9. hdu3491最小割转最大流+拆点

    题意:求最小割,即求最大流即可.此题之关键为拆点(限制在点),每条边都是双向边,注意一下. 未1A原因:在拆点之后添加边的过程中,要注意,出去的是i`,进来的是i,!!所以,写addegde函数时候 ...

随机推荐

  1. web端常见兼容性问题整理

    一.html和css 各浏览器的默认内外边距不一致问题 最明显的是ul标签内外边距问题,ul标签在IE-7中,有个默认的外边距,但是在IE8以上及其他浏览器中有个默认的内边距. 解决办法:*{marg ...

  2. Selenium搭配TestNG

    用Maven来构建TestNG依赖: <dependency> <groupId>org.testng</groupId> <artifactId>te ...

  3. Jenkins - 持续集成部署

    1. 安装svn:用于checkout源码 (1)yum 安装:yum -y install subversion (2)查看svn版本信息:svnserver --version 2. 安装jdk ...

  4. APP功能性测试-3

    定义:兼容测试就是指软件在特定的硬件平台,不同的应用软件之间,不同的操作系统平台上,不同的网络等环境中是否能够正常的运行的测试  (会不会产生不兼容) 兼容性测试的作用 进一步提高产品质量 和其他软件 ...

  5. 爬取妹子图(requests + BeautifulSoup)

    刚刚入门爬虫,今天先对于单个图集进行爬取,过几天再进行翻页爬取. 使用requests库和BeautifulSoup库 目标网站:妹子图 今天是对于单个图集的爬取,就选择一个进行爬取,我选择的链接为: ...

  6. Markdown常用的几种语法

    在VScode上面写的,现将代码粘贴如下:(在VScode里运行下即可) # Markdown语法 # Ctrl + k v 打开侧边预览 ## 一.加粗斜体删除线 **这是要加粗的文字** *这是要 ...

  7. 数据挖掘算法:DBSCAN算法的C++实现

    (期末考试快到了,所以比较粗糙,请各位读者理解..) 一.    概念 DBSCAN是一种产生划分聚类的基于密度的聚类算法,簇的个数由算法自动地确定.低密度区域中的点被视为噪声而忽略,因此DBSCAN ...

  8. 目标检测之Faster-RCNN的pytorch代码详解(模型训练篇)

    本文所用代码gayhub的地址:https://github.com/chenyuntc/simple-faster-rcnn-pytorch  (非本人所写,博文只是解释代码) 好长时间没有发博客了 ...

  9. win7 C/C++,QT安装环境总结

    1. 安装VMware,但是不能用,发现是权限问题,解决方式:使用管理员运行模式即可: 2. 安装win7 ultimate x64,找了半天找不到密钥,只要用激活软件,目前来说系统可用 3. 安装 ...

  10. springMVC笔记一

    第一章 回顾JavaWeb中的MVC设计模式 1)MVC这种设计模式,不光运用于Web领域,而且也能用于非Web领域 2)今天说的MVC特指一种表现层设计模式,不限于Java语言 第二章 回顾stru ...