题目链接

给你一个数字梯形, 最上面一层m个数字, 然后m+1,......m+n-1个。 n是层数。 在每个位置, 可以向左下或右下走。然后让你从最顶端的m个数字开始, 走出m条路径, 使得路过的数字总和最大。

给你三种规则, 第一种是,m条路径完全不能相交。 第二种是可以在数字处相交。 第三种是可以在数字或边的地方相交, 相当于没有限制。让你输出在这三种情况下的最大值分别是多少。

第一种, 因为完全不能相交, 所以我们将每个点拆成两个点x, x', x向x'连一条权值为1, 费用为-a[i][j]的边。 x'向可以到达的y连一条权值1, 费用0的边。 这样保证只走一次。

第二种, 可以在点的地方相交, 那x向x'连的那条边权值就可以放松为m。 其他不变。

第三种, 不光x向x'连的边权值可以放松, x'向y连得边权值也可以放松为m。

然后就可以得出答案了。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <complex>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef complex <double> cmx;
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-;
const int mod = 1e9+;
const int inf = ;
const int dir[][] = { {-, }, {, }, {, -}, {, } };
const int maxn = 2e5+;
int num, head[maxn*], s, t, n, nn, dis[maxn], flow, cost, cnt, cap[maxn], q[maxn], cur[maxn], vis[maxn], m, a[][];
struct node
{
int to, nextt, c, w;
node(){}
node(int to, int nextt, int c, int w):to(to), nextt(nextt), c(c), w(w) {}
}e[maxn*];
int spfa() {
int st, ed;
st = ed = ;
mem2(dis);
++cnt;
dis[s] = ;
cap[s] = inf;
cur[s] = -;
q[ed++] = s;
while(st<ed) {
int u = q[st++];
vis[u] = cnt-;
for(int i = head[u]; ~i; i = e[i].nextt) {
int v = e[i].to, c = e[i].c, w = e[i].w;
if(c && dis[v]>dis[u]+w) {
dis[v] = dis[u]+w;
cap[v] = min(c, cap[u]);
cur[v] = i;
if(vis[v] != cnt) {
vis[v] = cnt;
q[ed++] = v;
}
}
}
}
if(dis[t] == inf)
return ;
cost += dis[t]*cap[t];
flow += cap[t];
for(int i = cur[t]; ~i; i = cur[e[i^].to]) {
e[i].c -= cap[t];
e[i^].c += cap[t];
}
return ;
}
int mcmf() {
flow = cost = ;
while(spfa())
;
return cost;
}
void add(int u, int v, int c, int val) {
e[num] = node(v, head[u], c, val); head[u] = num++;
e[num] = node(u, head[v], , -val); head[v] = num++;
}
void init() {
mem1(head);
num = cnt = ;
mem(vis);
}
int getnum(int x, int y)
{
return (m+(x-)+m)*(x)/+y+;
}
void solve()
{
init();
t = +(*m+n-)*n;
s = ;
int sum = (*m+n-)*n/;
for(int i = ; i < n; i++) {
for(int j = ; j < m+i; j++) {
if(!i) {
add(s, j+, , );
}
int x = getnum(i, j);
add(x, x+sum, , -a[i][j]);
if(i != n-) {
int nxt = getnum(i+, j);
add(x+sum, nxt, , );
add(x+sum, nxt+, , );
}
if(i == n-) {
add(x+sum, t, , );
}
}
}
cout<<-mcmf()<<endl;
init();
for(int i = ; i < n; i++) {
for(int j = ; j < m+i; j++) {
if(!i) {
add(s, j+, , );
}
int x = getnum(i, j);
add(x, x+sum, m, -a[i][j]);
if(i != n-) {
int nxt = getnum(i+, j);
add(x+sum, nxt, , );
add(x+sum, nxt+, , );
}
if(i == n-) {
add(x+sum, t, m, );
}
}
}
cout<<-mcmf()<<endl;
init();
for(int i = ; i < n; i++) {
for(int j = ; j < m+i; j++) {
if(!i) {
add(s, j+, , );
}
int x = getnum(i, j);
add(x, x+sum, m, -a[i][j]);
if(i < n-) {
int nxt = getnum(i+, j);
add(x+sum, nxt, m, );
add(x+sum, nxt+, m, );
} else {
add(x+sum, t, m, );
}
}
}
cout<<-mcmf()<<endl;
}
int main()
{
cin>>m>>n;
for(int i = ; i < n; i++) {
for(int j = ; j < m+i; j++) {
scanf("%d", &a[i][j]);
}
}
solve();
return ;
}

codevs 1913 数字梯形问题 费用流的更多相关文章

  1. 2018.10.15 loj#6010. 「网络流 24 题」数字梯形(费用流)

    传送门 费用流经典题. 按照题目要求建边. 为了方便我将所有格子拆点,三种情况下容量分别为111,infinfinf,infinfinf,费用都为validi,jval_{id_{i,j}}valid ...

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

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

  3. 【wikioi】1913 数字梯形问题(费用流)

    http://wikioi.com/problem/1913/ 如果本题没有询问2和3,那么本题和蚯蚓那题一模一样.http://www.cnblogs.com/iwtwiioi/p/3935039. ...

  4. 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

    [bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后 ...

  5. 【BZOJ4514】数字配对(费用流)

    题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci× ...

  6. bzoj4514: [Sdoi2016]数字配对(费用流)

    传送门 ps:费用流增广的时候费用和流量打反了……调了一个多小时 每个数只能参与一次配对,那么这就是一个匹配嘛 我们先把每个数分解质因数,记质因子总个数为$cnt_i$,那如果$a_i/a_j$是质数 ...

  7. [SDOI2016]数字配对(费用流+贪心+trick)

    重点是如何找到可以配对的\(a[i]\)和\(a[j]\). 把\(a[i]\)分解质因数.设\(a[i]\)分解出的质因数的数量为\(cnt[i]\). 设\(a[i]\geq a[j]\) 那么\ ...

  8. BZOJ4514 [Sdoi2016]数字配对 【费用流】

    题目 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×c ...

  9. COGS738 [网络流24题] 数字梯形(最小费用最大流)

    题目这么说: 给定一个由n 行数字组成的数字梯形如下图所示.梯形的第一行有m 个数字.从梯形的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径.规则1:从梯形的 ...

随机推荐

  1. C++ 动态绑定

    1.为每一个包含虚函数的类设置一个虚表(VTABLE) 每当创建一个包含有虚函数的类或从包含虚函数的类派生一个类时,编译器就会为这个类创建一个VTABLE.在VTABLE中,编译器放置了这个类中,或者 ...

  2. bluestacks安装安卓引擎时出现2502 2503错误的解决办法

    2503代表工作站无法启动.2502代表下面的程序调用不支持的MS-DOS函数. 以管理员身份运行命令提示符在经典桌面使用快捷键Win+X,出现一个菜单,选择“命令提示符(管理员) ”即可以以管理员身 ...

  3. JavaMail简单接收邮件

    一个简单的例子,收取所有邮件并在控制台输出. package cn.jmail.test; import java.io.*; import java.util.*; import javax.mai ...

  4. USB驱动开发

    1.usb特点 2.usb class 3.

  5. weblogic配置domain和删除domain

    weblogic创建域的过程比较简单,但是在创建域之前一定要注意不能存在重名的domain. Domain简单定义为:是一个逻辑管理单元,Domain下面包含着weblogic应用服务器中的所有东西, ...

  6. SQL Server 找出值得优化的语句

    方法 1. sys.dm_exec_qurey_stats 返回 SQL Server 中缓存查询计划的聚合性能统计信息. 缓存计划中的每个查询语句在该视图中对应一行, 并且行的生存期与计划本身相关联 ...

  7. IDEA12 KeyGen Download List

    When you use IDEA to develop Java, you can use the following file to generate lincese. Because CNBlo ...

  8. 打开本地STL文件并创建webgl使用的geometry

    需求 打开本地STL文件 一个独立基于webgl的viewer,会被别的网站重用 将打开文件的数据传输给viewer,并且在文件加载的时候显示进度条 解决方案 #1可以使用传统的html5 api来打 ...

  9. android---EditText黄色边框

    http://liuzhichao.com/p/612.html 自定义android控件EditText边框背景 柳志超博客 » Program » Andriod » 自定义android控件Ed ...

  10. js的体会

    关于观察者模式的核心是: 回调函数, 传递函数名作为参数,或者是传递变量,然后调用其函数名. 关于闭包的核心是 闭包的函数是全局变量之下的函数, 而非闭包的函数是局部变量. <script> ...