#6010. 「网络流 24 题」数字梯形

 

题目描述

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

分别遵守以下规则:

  1. 从梯形的顶至底的 m mm 条路径互不相交;
  2. 从梯形的顶至底的 m mm 条路径仅在数字结点处相交;
  3. 从梯形的顶至底的 m mm 条路径允许在数字结点相交或边相交。

输入格式

第 1 11 行中有 2 22 个正整数 m mm 和 n nn,分别表示数字梯形的第一行有 m mm 个数字,共有 n nn 行。接下来的 n nn 行是数字梯形中各行的数字。
第 1 11 行有 m mm 个数字,第 2 22 行有 m+1 m + 1m+1 个数字 ……

输出格式

将按照规则 1,规则 2,和规则 3 计算出的最大数字总和并输出,每行一个最大总和。

样例

样例输入

2 5
2 3
3 4 5
9 10 9 1
1 1 10 1 1
1 1 10 12 1 1

样例输出

66
75
77

数据范围与提示

1≤m,n≤20 1 \leq m, n \leq 201≤m,n≤20

code

 #include<cstdio>
#include<algorithm>
#include<cstring> using namespace std;
const int N = ;
const int INF = 1e9; struct Edge{
int u,v,f,c,nxt;
Edge(){}
Edge(int a,int b,int flow,int cost,int nt) {
u = a;v = b;f = flow;c = cost;nxt = nt;
}
}e[];
int head[N],dis[N],q[],pre[N],a[][],b[][];
bool vis[N];
int n,m,S,T,tn,L,R,Mc,ans,tot; inline char nc() {
static char buf[],*p1 = buf,*p2 = buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,,stdin),p1==p2) ? EOF :*p1++;
}
inline int read() {
int x = ,f = ;char ch=nc();
for (; ch<''||ch>''; ch=nc()) if(ch=='-')f=-;
for (; ch>=''&&ch<=''; ch=nc()) x=x*+ch-'';
return x*f;
}
void add_edge(int u,int v,int f,int c) {
e[++tot] = Edge(u,v,f,c,head[u]);head[u] = tot;
e[++tot] = Edge(v,u,,-c,head[v]);head[v] = tot;
}
bool spfa() {
for (int i=; i<=T; ++i) vis[i]=false,dis[i]=INF;
L = ;R = ;
dis[S] = ;
q[++R] = S;vis[S] = true;pre[S] = ;
while (L <= R) {
int u = q[L++];
for (int i=head[u]; i; i=e[i].nxt) {
int v = e[i].v;
if (dis[v]>dis[u]+e[i].c && e[i].f > ) {
dis[v] = dis[u] + e[i].c;
pre[v] = i;
if (!vis[v]) q[++R] = v,vis[v] = true;
}
}
vis[u] = false;
}
return dis[T]!=INF;
}
void mcf() {
int zf = INF;
for (int i=T; i!=S; i=e[pre[i]].u)
zf = min(zf,e[pre[i]].f);
for (int i=T; i!=S; i=e[pre[i]].u)
e[pre[i]].f -= zf,e[pre[i]^].f += zf;
Mc += dis[T]*zf;
}
int work() {
Mc = ;
while (spfa()) mcf();
printf("%d\n",-Mc);
}
void init() {
tot = ;
memset(head,,sizeof(head));
}
void build_1() {
init();
S = tn + tn + ;T = tn + tn + ;
for (int i=; i<=n; ++i)
for (int j=; j<=m+i-; ++j) {
add_edge(b[i][j],b[i][j]+tn,,-a[i][j]);
add_edge(b[i][j]+tn,b[i+][j],,);
add_edge(b[i][j]+tn,b[i+][j+],,);
if (i==) add_edge(S,b[i][j],,);
if (i==n) add_edge(b[i][j]+tn,T,,);
}
}
void build_2() {
init();
S = tn + ;T = tn + ;
for (int i=; i<=n; ++i) {
for (int j=; j<=m+i-; ++j) {
add_edge(b[i][j],b[i+][j],,-a[i][j]);
add_edge(b[i][j],b[i+][j+],,-a[i][j]);
if (i==) add_edge(S,b[i][j],,);
if (i==n) add_edge(b[i][j],T,INF,-a[i][j]);
}
}
}
void build_3() {
init();
S = tn + ;T = tn + ;
for (int i=; i<=n; ++i) {
for (int j=; j<=m+i-; ++j) {
add_edge(b[i][j],b[i+][j],INF,-a[i][j]);
add_edge(b[i][j],b[i+][j+],INF,-a[i][j]);
if (i==) add_edge(S,b[i][j],,);
if (i==n) add_edge(b[i][j],T,INF,-a[i][j]);
}
}
}
int main() {
m = read(),n = read();
for (int i=; i<=n; ++i)
for (int j=; j<=m+i-; ++j) a[i][j] = read(),b[i][j] = ++tn; build_1();work();
build_2();work();
build_3();work();
return ;
}

最新文章

  1. freeCAD下载与安装
  2. hdoj 1022 Train Problem I
  3. 【POJ水题完成表】
  4. 我所常用的ajax调用格式
  5. Mysql 5.7.7
  6. [HZNUOJ1524]排队买票(DP)
  7. 【转】A*寻路算法 C++实现
  8. Ceph Jewel 10.2.3 环境部署
  9. 【面试题001-补充】C++ MyString类的封装
  10. Quartz 第三课 More About Jobs &amp; JobDetails(官方文档翻译)
  11. jquery文字左右滚动
  12. Android Developers:拖动和缩放
  13. DataGrid列的合并
  14. apt-get命令学习
  15. Windows SVN变更发送邮件通知(JAVA实现)
  16. PAT乙级 1065. 单身狗(25) by Python
  17. uva-519-拼图
  18. python 判断一个数字是否为3的幂
  19. iOS Sprite Kit教程之编写程序以及Xcode的介绍
  20. SD卡路径问题以及如何获取SDCard 内存

热门文章

  1. Java 编码规范有感
  2. ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第八天(非原创)
  3. oracle报错:ORA-01658(转自52斋347)
  4. 如何避开JavaScript浮点数计算精度问题(如0.1+0.2!==0.3)
  5. eros 修改 android上原生picker的颜色的呢
  6. winform 自适应屏幕分辨率具体操作和注意事项
  7. ASP.NET Dev ASPxGridView控件使用 ASP.NET水晶报表打印
  8. Ubuntu 14.04 安装caffe深度学习框架
  9. linux 命令——23 目录结构
  10. slenium的xpath几种定位方式