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\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成 ...
随机推荐
- Oracle 静默安装 oracle 12c
[oracle@local12cdg app]$ id oracleuid=501(oracle) gid=501(oinstall) groups=501(oinstall),502(dba)[or ...
- 部署和调优 1.8 samba 部署和优化-2
Samba 可以实现 Linux 和 Windows 机器相互共享文件,这对我们来说是非常实用的.下面做几个实践,来了解samba,注意:在实践之前,请先检测 Selinux 是否关闭,否则可能会实践 ...
- Logstash-2.4.1的下载(图文详解)
第一步:进入Elasticsearch的官网 https://www.elastic.co/ 第二步:点击downloads https://www.elastic.co/downloads 第三步: ...
- PHP的count(数组)和strlen(字符串)的内部实现
PHP的count(数组)和strlen(字符串)的内部实现上是直接显示一个长度变量,还是重头依次数一遍有多少个元素?关乎我理解这2个函数的效率..希望高人能从php的c源码上讲一讲.没有源码看过源码 ...
- C++面向对象类的实例题目六
问题描述: 编写一个程序计算两个给定长方形的面积,其中在设计类成员函数addarea()(用于计算两个长方形的总面积)时使用对象作为参数. 程序代码: #include<iostream> ...
- aspose ppt转图片
如果直接转图片,会很模糊采用先将ppt转pdf,在通过pdf转图片,这样出来的结果就非常清晰 var pptFileName = "公司网络及计算机使用与要求.pptx"; Pre ...
- JavaWeb_泛型(Generic)
JDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换,这样不可避免的就会引发程序的一些安全性问题.例如: ArrayList list = new ArrayList ...
- 《Head First Servlets & JSP》-4-请求和响应
Servlet生命周期 生命周期三大重要时刻 Servlet集成结构: 方法 init() service() doGet()/goPost() 何时调用 Servlet实例被创建之后.为客户请求提供 ...
- php数据连接
<?php header("Content-type: text/html;charset=utf-8");//设置编码格式为UTF-8 error_reporting(E_ ...
- Java50道经典习题-程序28 排序算法
题目:对10个数进行排序分析:可以利用选择法,即从后9个比较过程中,选择一个最小的与第一个元素交换, 下次类推,即用第二个元素与后8个进行比较,并进行交换. public class Prog28 { ...