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\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成 ...
随机推荐
- jenkins学习 02 jenkins安装与配置
1: Jenkins安装 在最简单的情况下,Jenkins 只需要两个步骤: (1)下载最新的版本(一个 WAR 文件).Jenkins官方网址: http://Jenkins-ci.org/ (2 ...
- 侯捷STL学习(一)--顺序容器测试
开始跟着<STL源码剖析>的作者侯捷真人视频,学习STL,了解STL背后的真实故事! 视频链接:侯捷STL 还有很大其他视频需要的留言 第一节:STL版本和重要资源 STL和标准库的区别 ...
- springmvc----demo1---hello---bai
import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import ...
- leetcode Single Number II - 位运算处理数组中的数
题目描述: 给定一个包含n个整数的数组,除了一个数出现一次外所有的整数均出现三次,找出这个只出现一次的整数. 题目来源: http://oj.leetcode.com/problems/single- ...
- system中有空格怎么办
原始路径: C:\\Program Files\\putty\\putty.exe 改为: char *cmd="C:\\\"Program Files\"\\putty ...
- Sandbox简介和路径获取
一.简介 iOS的沙盒机制,每个应用只能访问自己应用目录下的文件.iOS应用产生的内容,如文件.缓存内容等都必须存储在自己的沙盒内.默认情况下,每个沙盒含有3个文件夹:Documents, Libra ...
- LAMP 3.1 mysql的root密码重置
给mysql设置密码 /usr/local/mysql/bin/mysql -uroot 可以直接登录mysql 设置密码 /usr/local/mysql/bin/mysqladmin -uroot ...
- IE9以及IE9以下,无法执行innerHTML这一操作的解决方法
例如:在select下无法用innerHTML添加<option> 解决代码: var s=document.createElement("option"); s.te ...
- 【转】Sublime Text2中的快捷键一览表(Sublime 键盘快捷键大全 )
Sublime Text 提供了无比强大的快捷键阵容,如果能够在Coding的时候灵活的使用快捷键,将能够使得你的效率倍增,相信在不久的将来,Sublime Text将是你跨平台使用的最佳Coding ...
- Codeforces 1108F (MST Unification) (树上倍增 or 改进 kruksal)
题意:给你一张n个节点和m条边的无向连通图, 你可以执行很多次操作,对某一条边的权值+1(对于每条边,可以不加,可以无限次加),问至少进行多少次操作,可以使这张图的最小生成树变得唯一,并且最小生成树的 ...