P4013 数字梯形问题
\(\color{#0066ff}{题目描述}\)
给定一个由 \(n\) 行数字组成的数字梯形如下图所示。
梯形的第一行有 \(m\) 个数字。从梯形的顶部的 \(m\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
分别遵守以下规则:
1.从梯形的顶至底的 \(m\) 条路径互不相交;
2.从梯形的顶至底的 \(m\) 条路径仅在数字结点处相交;
3.从梯形的顶至底的 \(m\) 条路径允许在数字结点相交或边相交。
\(\color{#0066ff}{输入格式}\)
第 \(1\) 行中有 \(2\) 个正整数 \(m\) 和 \(n\),分别表示数字梯形的第一行有 \(m\) 个数字,共有 \(n\) 行。接下来的 \(n\) 行是数字梯形中各行的数字。
第 \(1\) 行有 \(m\) 个数字,第 \(2\) 行有 \(m+1\) 个数字,以此类推。
\(\color{#0066ff}{输出格式}\)
将按照规则 \(1\),规则 \(2\),和规则 \(3\) 计算出的最大数字总和并输出,每行一个最大总和。
\(\color{#0066ff}{输入样例}\)
2 5
2 3
3 4 5
9 10 9 1
1 1 10 1 1
1 1 10 12 1 1
\(\color{#0066ff}{输出样例}\)
66
75
77
\(\color{#0066ff}{数据范围与提示}\)
\(1\leq m,n\leq 20\)
\(\color{#0066ff}{题解}\)
把点权转成边权,每个位置拆点
第一问,所有容量均为1,这样都不会重复
x流到y',让y'连向y,这样进行下次流动
每一个点向下一层到的点连边,最后一层向终点连边
第二问,因为点可以重复,要考虑终点!!!
把x'到x的边改成inf,这样每个点可以接受来自上面多个点的流
还要把连向t的流改成inf,终点位置可能重合!
第三问,中间的所有边改成inf就行,因为终究还是m条路,所以起点的连边还是1
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define _ 0
#define LL long long
inline LL in() {
LL x = 0, f = 1; char ch;
while (!isdigit(ch = getchar())) (ch == '-') && (f = -f);
while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
return x * f;
}
const int maxn = 105000;
struct node {
int to, dis, can;
node *nxt, *rev;
node(int to = 0, int dis = 0, int can = 0, node *nxt = NULL) : to(to), dis(dis), can(can), nxt(nxt) {}
};
const int inf = 0x7fffffff;
int n, m, s, t, cnt;
std::queue<int> q;
typedef node *nod;
nod head[maxn], road[maxn];
bool vis[maxn];
int dis[maxn], change[maxn], mp[505][550], id[550][505];
inline void add(int from, int to, int can, int dis) {
nod o = new node(to, dis, can, head[from]);
head[from] = o;
}
inline void link(int from, int to, int can, int dis) {
add(from, to, can, dis);
add(to, from, 0, -dis);
head[from]->rev = head[to];
head[to]->rev = head[from];
}
inline bool spfa() {
for (int i = s; i <= t; i++) dis[i] = -inf, change[i] = inf;
dis[s] = 0;
q.push(s);
while (!q.empty()) {
int tp = q.front();
q.pop();
vis[tp] = false;
for (nod i = head[tp]; i; i = i->nxt) {
if (dis[i->to] < dis[tp] + i->dis && i->can > 0) {
dis[i->to] = dis[tp] + i->dis;
change[i->to] = std::min(change[tp], i->can);
road[i->to] = i->rev;
if (!vis[i->to])
vis[i->to] = true, q.push(i->to);
}
}
}
return change[t] != inf;
}
inline int mcmf() {
int flow = 0, cost = 0;
while (spfa()) {
flow += change[t];
cost += change[t] * dis[t];
for (int i = t; i != s; i = road[i]->to) {
road[i]->can += change[t];
road[i]->rev->can -= change[t];
}
}
return cost;
}
inline void partone() {
for (int i = 1; i <= m; i++) link(s, id[1][i], 1, mp[1][i]);
for (int i = 1; i <= m + n - 1; i++) link(id[n][i] + cnt, t, 1, 0);
for (int i = 1; i <= cnt; i++) link(i + cnt, i, 1, 0);
for (int i = 1; i <= n - 1; i++)
for (int j = 1; j <= m + i - 1; j++)
link(id[i][j], id[i + 1][j] + cnt, 1, mp[i + 1][j]),
link(id[i][j], id[i + 1][j + 1] + cnt, 1, mp[i + 1][j + 1]);
printf("%d\n", mcmf());
}
inline void parttwo() {
for (int i = s; i <= t; i++) head[i] = NULL;
for (int i = 1; i <= m; i++) link(s, id[1][i], 1, mp[1][i]);
for (int i = 1; i <= m + n - 1; i++) link(id[n][i] + cnt, t, inf, 0);
for (int i = 1; i <= cnt; i++) link(i + cnt, i, inf, 0);
for (int i = 1; i <= n - 1; i++)
for (int j = 1; j <= m + i - 1; j++)
link(id[i][j], id[i + 1][j] + cnt, 1, mp[i + 1][j]),
link(id[i][j], id[i + 1][j + 1] + cnt, 1, mp[i + 1][j + 1]);
printf("%d\n", mcmf());
}
inline void partthree() {
for (int i = s; i <= t; i++) head[i] = NULL;
for (int i = 1; i <= m; i++) link(s, id[1][i], 1, mp[1][i]);
for (int i = 1; i <= m + n - 1; i++) link(id[n][i] + cnt, t, inf, 0);
for (int i = 1; i <= cnt; i++) link(i + cnt, i, inf, 0);
for (int i = 1; i <= n - 1; i++)
for (int j = 1; j <= m + i - 1; j++)
link(id[i][j], id[i + 1][j] + cnt, inf, mp[i + 1][j]),
link(id[i][j], id[i + 1][j + 1] + cnt, inf, mp[i + 1][j + 1]);
printf("%d\n", mcmf());
}
int main() {
m = in(), n = in();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m + i - 1; j++) mp[i][j] = in(), id[i][j] = ++cnt;
s = 0, t = (cnt << 1) + 1;
partone(), parttwo(), partthree();
return 0;
}
好像突然清真了。。。
P4013 数字梯形问题的更多相关文章
- P4013 数字梯形问题 网络流二十四题
P4013 数字梯形问题 题目描述 给定一个由 nn 行数字组成的数字梯形如下图所示. 梯形的第一行有 m 个数字.从梯形的顶部的 m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形 ...
- P4013 数字梯形问题 网络流
题目描述 给定一个由 nn 行数字组成的数字梯形如下图所示. 梯形的第一行有 mm 个数字.从梯形的顶部的 mm 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径. 分别 ...
- 洛谷P4013数字梯形问题——网络流24题
题目:https://www.luogu.org/problemnew/show/P4013 最大费用最大流裸题: 注意:在第二种情况中,底层所有点连向汇点的边容量应该为inf,因为可以有多条路径结束 ...
- 洛谷P4013 数字梯形问题(费用流)
传送门 两个感受:码量感人……大佬nb…… 规则一:$m$条路径都不相交,那么每一个点只能经过一次,那么考虑拆点,把每一个点拆成$A_{i,j}$和$B_{i,j}$,然后两点之间连一条容量$1$,费 ...
- 洛谷P4013 数字梯形问题(费用流)
题意 $N$行的矩阵,第一行有$M$个元素,第$i$行有$M + i - 1$个元素 问在三个规则下怎么取使得权值最大 Sol 我只会第一问qwq.. 因为有数量的限制,考虑拆点建图,把每个点拆为$a ...
- 洛谷 P4013 数字梯形问题【最大费用最大流】
第一问:因为每个点只能经过一次,所以拆点限制流量,建(i,i',1,val[i]),然后s向第一行建(s,i,1,0),表示每个点只能出发一次,然后最后一行连向汇点(i',t,1,0),跑最大费用最大 ...
- 洛谷 P4013 数字梯形问题
->题目链接 题解: 网络流. #include<cstdio> #include<iostream> #include<queue> #include< ...
- luogu P4013 数字梯形问题
三倍经验,三个条件,分别对应了常见的3种模型,第一种是限制每个点只能一次且无交点,我们可以把这个点拆成一个出点一个入点,capacity为1,这样就限制了只选择一次,第二种是可以有交点,但不能有交边, ...
- 【费用流】【网络流24题】【P4013】 数字梯形问题
Description 给定一个由 \(n\) 行数字组成的数字梯形如下图所示. 梯形的第一行有 \(m\) 个数字.从梯形的顶部的 \(m\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成 ...
随机推荐
- 转:MongoDB · 引擎特性 · journal 与 oplog,究竟谁先写入?
转:MongoDB · 引擎特性 · journal 与 oplog,究竟谁先写入? 数据库内核月报 链接:http://mysql.taobao.org/monthly/2018/05/07/ Mo ...
- maven如何过滤占位符
今天遇到一个问题,就是properties文件中赋值用的这种形式${xxx},真正的值是配置在pom的profile中,但是未生效. 后来找到原因,原来是pom中少了一段代码: <build&g ...
- GridControl 隐藏Drag a column header here to group by that column
解决方案: 打开设计器,找到OptionsView,往下拉设置showGroupPanel为false
- iOS 给Main.storyboard 添加button 事件《转》
XCODE中使用Main.Storyboard拉入控件并实现事件(Swift语言) 如何在XCODE中的Main.Storyboard内拉入控件并实现一个简单的效果呢?本人由于刚接触Swift语言 ...
- 用JS,打印正立三角形
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- MongoDB中的查询
MongoDB中文文档:http://docs.mongoing.com/manual-zh/contents.html 这里以集合名称为test为例,数据库通过for循环插入一些测试数据,键分别为: ...
- MySQL 删除字段数据某关键字后的所有数据
),'开发商') WHERE Compay LIKE '%开发商%'; sql附上
- javascript作用域原理
问题的提出 首先看一个例子: var name = 'laruence'; function echo() { alert(name); var name = 'eve'; alert(name); ...
- PopupWindow-----点击弹出 PopupWindow 初始化菜单
/** * 点击弹出 PopupWindow 初始化菜单 */ private void initPopupWindow() { PopupWindowAdapter adapter = new Po ...
- android官方手册学习笔记
数据存储 在提交sharedpreference 修改的时候,用apply代替commit 避免UI线程阻塞 设备兼容 系统会自动根据当前屏幕的大小等,在相应的文件夹里去找资源,如large等等 ...