\(\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 数字梯形问题的更多相关文章

  1. P4013 数字梯形问题 网络流二十四题

    P4013 数字梯形问题 题目描述 给定一个由 nn 行数字组成的数字梯形如下图所示. 梯形的第一行有 m 个数字.从梯形的顶部的 m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形 ...

  2. P4013 数字梯形问题 网络流

    题目描述 给定一个由 nn 行数字组成的数字梯形如下图所示. 梯形的第一行有 mm 个数字.从梯形的顶部的 mm 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径. 分别 ...

  3. 洛谷P4013数字梯形问题——网络流24题

    题目:https://www.luogu.org/problemnew/show/P4013 最大费用最大流裸题: 注意:在第二种情况中,底层所有点连向汇点的边容量应该为inf,因为可以有多条路径结束 ...

  4. 洛谷P4013 数字梯形问题(费用流)

    传送门 两个感受:码量感人……大佬nb…… 规则一:$m$条路径都不相交,那么每一个点只能经过一次,那么考虑拆点,把每一个点拆成$A_{i,j}$和$B_{i,j}$,然后两点之间连一条容量$1$,费 ...

  5. 洛谷P4013 数字梯形问题(费用流)

    题意 $N$行的矩阵,第一行有$M$个元素,第$i$行有$M + i - 1$个元素 问在三个规则下怎么取使得权值最大 Sol 我只会第一问qwq.. 因为有数量的限制,考虑拆点建图,把每个点拆为$a ...

  6. 洛谷 P4013 数字梯形问题【最大费用最大流】

    第一问:因为每个点只能经过一次,所以拆点限制流量,建(i,i',1,val[i]),然后s向第一行建(s,i,1,0),表示每个点只能出发一次,然后最后一行连向汇点(i',t,1,0),跑最大费用最大 ...

  7. 洛谷 P4013 数字梯形问题

    ->题目链接 题解: 网络流. #include<cstdio> #include<iostream> #include<queue> #include< ...

  8. luogu P4013 数字梯形问题

    三倍经验,三个条件,分别对应了常见的3种模型,第一种是限制每个点只能一次且无交点,我们可以把这个点拆成一个出点一个入点,capacity为1,这样就限制了只选择一次,第二种是可以有交点,但不能有交边, ...

  9. 【费用流】【网络流24题】【P4013】 数字梯形问题

    Description 给定一个由 \(n\) 行数字组成的数字梯形如下图所示. 梯形的第一行有 \(m\) 个数字.从梯形的顶部的 \(m\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成 ...

随机推荐

  1. CreateWaitableTimer和SetWaitableTimer

    负值表示相对时间,正值表示绝对时间,定时器精度为100ns (1ns=1/10亿 s),所以 -50000000 代表5秒,详见MSDN. 程序一为自动重置(先等待5秒,然后每1秒输出一次): #in ...

  2. linux命令-sudo普通用户拥有root权限

    普通用户权限不够 [root@wangshaojun ~]# su - dennywang[dennywang@wangshaojun ~]$ ls /root/ls: 无法打开目录/root/: 权 ...

  3. [Python Study Notes]水平柱状图绘制

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...

  4. ssh整合(dao使用hibernateTemplate)

  5. Codeforces #504(div1+div2) 1023D Array Restoration(线段树)

    题目大意:给你一个数组,数组是经过q次区间覆盖后的结果,第i次覆盖是把区间内的值赋值为i,其中有若干个地方数值未知(就是0),让你判断这个数组是否可以经过覆盖后得到的,如果可以,输出任意一种可行数组. ...

  6. 面试题: 1天的java面试题 已看1

    1,自我介绍下,我直接说的项目经历,(哪年在哪个公司呆过) 2,问是否有带过团队的经历,我说去年带过一次. 3,Struts是单例模式还是多例模式?我先说单例模式,后说多例模式. Struts1是单例 ...

  7. ROS Learning-023 (提高篇-001) 准备工作 --- 安装一些必要的软件包

    ROS 提高篇-001 - 准备工作 - 安装一些必要的软件 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 LTS ROS 版本 ...

  8. Ubuntu,kubuntu与xubuntu的差别 Ubuntu各版本主要差异

    Ubuntu各版本主要差异 Ubuntu官方考虑到使用者的不同需求,提供各种不同的发行版.虽然发布了几种版本的Ubuntu系统,但是它们的核心系统是一模一样的.可以这么说不同发行版的Ubuntu的区别 ...

  9. hBase-thrift 实践(java)

    参考官网: http://wiki.apache.org/hadoop/Hbase/ThriftApi 环境:hbase-0.98.1-cdh5.1.0,hadoop-2.3.0-cdh5.1.0,c ...

  10. PHP微信分享

    注意 : 分享需要认证微信订阅号或者服务号. php 代码(thinkphp): $appid='xxx';  $appsecret='xxxx';    $timestamp = time();   ...