[Vijos 1143]三取方格数
Description
设有N*N的方格图,我们将其中的某些方格填入正整数,
而其他的方格中放入0。
某人从图得左上角出发,可以向下走,也可以向右走,直到到达右下角。
在走过的路上,他取走了方格中的数。(取走后方格中数字变为0)
此人从左上角到右下角共走3次,试找出3条路径,使得取得的数总和最大。
Input
第一行:N (4<=N<=20)
接下来一个N*N的矩阵,矩阵中每个元素不超过80,不小于0
Output
Sample Input
4
1 2 3 4
2 1 3 4
1 2 3 4
1 3 2 4
Sample Output
39
题解(转载)
$DP$好题。
这里给出费用流的做法:
拆点建图,每一个点都拆成两个点,在这里就称为出点和入点。
出点和入点建两条边,一条费用为$s[i][j]$,流量为$1$;一条费用为$0$,流量为$inf$。(分别表示选择这个点和从这个点上经过)
将$(i,j)$的出点分别和$(i+1,j)$$(i,j+1)$的入点建边,流量为$inf$,费用为$0$。(表示行进)
跑一边最大费用最大流就可以了。
#include <set>
#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int INF = ~0u>>; int n;
int a[][];
struct tt{
int to, cost, next, cap;
}edge[];
int path[], top = -;
void Add(int u, int v, int cost, int cap);
int sta = , fin = ;
int min_cost_flow();
int SPFA(); int main(){
memset(path, -, sizeof(path));
scanf("%d", &n);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
scanf("%d", &a[i][j]);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++){
Add(i*n+j, (i+n)*n+j, a[i][j], );
Add(i*n+j, (i+n)*n+j, , INF);
if (i != n-) Add((i+n)*n+j, (i+)*n+j, , INF);
if (j != n-) Add((i+n)*n+j, i*n+j+, , INF);
}
Add(sta, , , );
Add((*n-)*n+n-, fin, ,);
printf("%d\n", min_cost_flow());
return ;
} void Add(int u, int v, int cost, int cap){
edge[++top].to = v;
edge[top].cost = cost;
edge[top].cap = cap;
edge[top].next = path[u];
path[u] = top;
edge[++top].to = u;
edge[top].cost = -cost;
edge[top].cap = ;
edge[top].next = path[v];
path[v] = top;
}
int min_cost_flow(){
int tolcost = ;
int tmp;
while (tmp = SPFA()) tolcost += tmp;
return tolcost;
}
int SPFA(){
int dist[];
memset(dist, , sizeof(dist)); dist[sta] = ; dist[fin] = -INF;
bool vis[] = {}; vis[sta] = ;
queue<int>Q;
while (!Q.empty()) Q.pop();
Q.push(sta);
int pre[] = {};
while (!Q.empty()){
int u = Q.front(); Q.pop(); vis[u]=;
for (int i = path[u]; i != -; i = edge[i].next){
int v = edge[i].to;
if (dist[v] < dist[u]+edge[i].cost && edge[i].cap > ){
dist[v] = dist[u]+edge[i].cost;
pre[v] = i;
if (!vis[v]){
vis[v] = ;
Q.push(v);
}
}
}
}
if (dist[fin] == -INF) return ;
int minflow = INF;
for (int i = fin; i != sta; i = edge[pre[i]^].to)
minflow = Min(minflow, edge[pre[i]].cap);
for (int i = fin; i != sta; i = edge[pre[i]^].to)
edge[pre[i]].cap -= minflow,
edge[pre[i]^].cap += minflow;
return dist[fin];
}
[Vijos 1143]三取方格数的更多相关文章
- 【动态规划】Vijos P1143 三取方格数(NOIP2000提高组)
题目链接: https://vijos.org/p/1143 题目大意: NxN的矩阵,每个值只能取一次,从(1,1)走到(n,n)走三次能取得的最大值. 题目思路: [动态规划] f[x1][y1] ...
- begin.BZOJ 1383: 三取方格数
题目链接:传送门 题目大意:给你一个矩阵,每个格子有一个值,现在你要从左上角走到右下角(走3次),使得经过路径的权值和最大. 每个格子的值只能取一次,取完后变为0,输出走完三次后最大的权值和. 题目思 ...
- POJ 3422 Kaka's Matrix Travels (K取方格数:最大费用流)
题意 给出一个n*n大小的矩阵,要求从左上角走到右下角,每次只能向下走或者向右走并取数,某位置取过数之后就只为数值0,现在求解从左上角到右下角走K次的最大值. 思路 经典的费用流模型:K取方格数. 构 ...
- Luogu2045 方格取数加强版(K取方格数) 费用流
题目传送门 题意:给出一个$N \times N$的方格,每个格子中有一个数字.你可以取$K$次数,每次取数从左上角的方格开始,每一次只能向右或向下走一格,走到右下角结束,沿路的方格中的数字将会被取出 ...
- poj 3422 洛谷P2045 K取方格数(方格取数加强版)
Description: 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来 ...
- POJ 3422 Kaka's Matrix Travels K取方格数
题目:给出n*n的方格矩阵,现在从左上方走m次到右下方,问m次能够获得的最大价值和. 分析:最大费用流.拆点进行限制每个格子只取一次,假设点x拆成 x,xx,右边(假设有)y,yy,下方(假设有)z, ...
- vijos 1563 疯狂的方格取数
P1653疯狂的方格取数 Accepted 标签:天才的talent[显示标签] 背景 Due to the talent of talent123,当talent123做完NOIP考了两次的二取 ...
- php实现求数组中出现次数超过一半的数字(isset($arr[$val]))(取不同数看剩)(排序取中)
php实现求数组中出现次数超过一半的数字(isset($arr[$val]))(取不同数看剩)(排序取中) 一.总结 1.if(isset($arr[$val])) $arr[$val]++; //1 ...
- 一个hin秀的小学三年级奥数题 [hin秀]
~~~~~~不知为何总会被小学的题虐哭QAQ,真的秀啊,毒害广大小朋友~~~~~~ 一个hin秀的小学三年级奥数题 [hin秀] 题目: 给出一个无限大的棋盘 n×n (n>0 , 是 ...
随机推荐
- IntelliJIDEA中如何使用JavaDoc
IntelliJ IDEA 12.1.6,本身提供了很好的 JavaDoc 生成功能,以及标准 JavaDoc 注释转换功能,其实质是在代码编写过程中,按照标准 JavaDoc 的注释要求,为需要暴露 ...
- DML数据操作语言之查询(一)
1.select语句基础 基本语句格式: select <列名>,.... from <表名>; select子句中列举出希望从表中查询出的列的名称,from子句则指定了选取 ...
- 22.C++- 继承与组合,protected访问级别
在C++里,通过继承和组合实现了代码复用,使得开发效率提高,并且能够通过代码看到事物的关系 组合比继承简单,所以在写代码时先考虑能否组合,再来考虑继承. 组合的特点 将其它类的对象作为当前类的成员使用 ...
- vue的简单tab
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" ...
- 搭建vue项目环境
前言 在开发本项目之前,我对vue,react,angular等框架了解,仅限于知道它们是什么框架,他们的核心是什么,但是并没有实际使用过(angular 1.0版本用过,因为太难用,所以对这类框架都 ...
- IDEA之Jrebel插件激活
问题: 码农日常中,热部署是必不可少的,而jrebel插件很好的实现热部署功能. IDEA下载jrebel插件,可以免费试用15天,但之后就无法使用.因为Jrebel是收费的. 解决方法: 楼主也是百 ...
- Java8-如何构建一个Stream
Stream的创建方式有很多种,除了最常见的集合创建,还有其他几种方式. List转Stream List继承自Collection接口,而Collection提供了stream()方法. List& ...
- Python内置函数(28)——iter
英文文档: iter(object[, sentinel]) Return an iterator object. The first argument is interpreted very dif ...
- ORM “杀器”之 JOOQ
ORM “杀器”之 JOOQ IN 后端编程,JAVA,敏捷开发,数据库 JOOQ是啥? JOOQ 是基于Java访问关系型数据库的工具包,轻量,简单,并且足够灵活,可以轻松的使用Java面向对象语法 ...
- 阿里云API网关(17)签名算法
网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...