偏序集上的最小链覆盖等价于求最长反链

最小不交链覆盖等于传递闭包后最小链覆盖

最小链覆盖大小等于点数减去二分图最大匹配大小

二分图最小点覆盖大小等于二分图匹配大小

二分图最小点覆盖与二分图最大独立集对偶

建图完后,这个二分图最大独立集等价于最长反链。

于是两道题

1143: [CTSC2008]祭祀river

求偏序集上的最长反链

转换成偏序集上的最小链覆盖

求个闭包,转换成最小路径覆盖,二分图匹配一发

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue> const int MAXN = 210;
const int MAXM = MAXN * MAXN * 2;
const int INF = 0x3f3f3f3f;
int head[MAXN], nxt[MAXM], to[MAXM], val[MAXM], tot = 1;
inline void addedge(int b, int e, int v) {
nxt[++tot] = head[b]; to[head[b] = tot] = e; val[tot] = v;
nxt[++tot] = head[e]; to[head[e] = tot] = b; val[tot] = 0;
}
std::queue<int> q;
int S, T, dis[MAXN];
bool bfs() {
for (int i = S; i <= T; ++i) dis[i] = 0;
dis[S] = 1; q.push(S);
while (!q.empty()) {
int t = q.front(); q.pop();
for (int i = head[t]; i; i = nxt[i])
if (val[i] && !dis[to[i]]) {
dis[to[i]] = dis[t] + 1;
q.push(to[i]);
}
}
return dis[T] > 0;
}
int dinic(int u, int minv) {
if (u == T || !minv) return minv;
int t, res = 0;
for (int i = head[u]; i; i = nxt[i])
if (val[i] && dis[to[i]] == dis[u] + 1 && (t = dinic(to[i], std::min(minv, val[i])))) {
val[i] -= t;
val[i ^ 1] += t;
res += t;
minv -= t;
if (!minv) break;
}
if (!res) dis[u] = -1;
return res;
} int n, m, t1, t2, f[MAXN][MAXN];
int main() {
scanf("%d%d", &n, &m);
S = 0, T = n << 1 | 1;
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &t1, &t2);
f[t1][t2] = true;
}
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
f[i][j] |= f[i][k] & f[k][j];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (f[i][j])
addedge(i, j + n, 1);
for (int i = 1; i <= n; ++i) {
addedge(S, i, 1);
addedge(i + n, T, 1);
}
int ans = n;
while (bfs()) ans -= dinic(S, INF);
printf("%d\n", ans);
return 0;
}

3997: [TJOI2015]组合数学

 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走。问至少走多少次才能将财宝捡完。此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完。

求偏序集上的最小链覆盖,转换为最长反链覆盖

于是只要DP出反链就好了,前(其实是后)缀和优化一下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> const int MAXN = 1010;
int f[MAXN][MAXN], suc[MAXN][MAXN], map[MAXN][MAXN], n, m;
inline void getmax(int & x, const int y) { if (x < y) x = y; } int main() {
int T; scanf("%d", &T);
while (T --> 0) {
scanf("%d%d", &n, &m);
for (int i = 0; i <= n + 1; ++i)
for (int j = 0; j <= m + 1; ++j)
f[i][j] = suc[i][j] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) scanf("%d", map[i] + j);
for (int j = m; j; --j) {
getmax(f[i][j], suc[i - 1][j + 1] + map[i][j]);
suc[i][j] = std::max(suc[i][j + 1], suc[i - 1][j]);
getmax(suc[i][j], f[i][j]);
}
}
printf("%d\n", suc[n][1]);
}
return 0;
}

最新文章

  1. 【目录】本博客其他.NET开源项目文章目录
  2. ppmoney 总结一
  3. asp.net mvc4 过滤器的简单应用:登录验证
  4. java的分层开发
  5. SQL初级第三课(下)
  6. 全渠道后端 : RFID在仓储物流中的运用
  7. .NET 命名规范 代码示例
  8. bash: ./device/nexell/tools/build.sh: 权限不够
  9. Linux的五个查找命令:find,locate,whereis,which,type
  10. Spring_DI利用set方法赋值Demo
  11. C++之------虚函数
  12. 帝国cms7.0调用出栏目下的东西
  13. ⒂bootstrap组件 折叠 基础案例
  14. SOFA 源码分析 — 自定义线程池原理
  15. glide 长方形图片显示圆角问题
  16. mysql练习----SUM and COUNT/zh图(二)
  17. python获取当前文件路径以及父文件路径
  18. Ubuntu修改时间时区
  19. springboot @Value 获取计算机中绝对路径文件的内容
  20. QT中添加 动态库(.so) 和 静态库 (.a) 的方法

热门文章

  1. SVN随笔记录(一)
  2. C++练习 | 基于栈的中缀算术表达式求值(double类型
  3. 移动端、pc端通用点击复制
  4. Leetcode简单题
  5. ajax异步刷新请求数据
  6. JS常用函数原理的实现
  7. mysql数据库表名区分大小写
  8. 指针、数组与sizeof运算符
  9. string::find_first_not_of
  10. 【CF451E】Devu and Flowers