NOIP 2014普及组 T4(话说一道PJ组的题就把我卡了一个多小时诶)

这道题在我看第一次的时候是没有意识到这是一道DP题的,然后就摁着DFS敲了好长时间,结果敲了一个TLE

这是DP!!!

下面开始进入正题

题目描述

给出如下定义:

  1. 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵。

例如,下面左图中选取第22、44行和第22、44、55列交叉位置的元素得到一个2 \times 32×3的子矩阵如右图所示。

9 3 3 3 9

9 4 8 7 4

1 7 4 6 6

6 8 5 6 9

7 4 5 6 1

的其中一个2 \times 32×3的子矩阵是

4 7 4

8 6 9

  1. 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的。

  2. 矩阵的分值:矩阵中每一对相邻元素之差的绝对值之和。

本题任务:给定一个nn行mm列的正整数矩阵,请你从这个矩阵中选出一个rr行cc列的子矩阵,使得这个子矩阵的分值最小,并输出这个分值。

输入输出格式

输入格式:

第一行包含用空格隔开的四个整数n,m,r,cn,m,r,c,意义如问题描述中所述,每两个整数之间用一个空格隔开。

接下来的nn行,每行包含mm个用空格隔开的整数,用来表示问题描述中那个nn行mm列的矩阵。

输出格式:

一个整数,表示满足题目描述的子矩阵的最小分值。

样例:
输入


输出


这道题就是将题目所给你的矩阵进行“选取”行与列的操作,从而得到所求的最大值的集合,但是重要的是我们不知道题目所给的行和列的值是多少,因此我们可以对此进行一个循环中的判断操作,在选出来这个行之后再去考虑列的情况,从而得出最优决策。

这个地方还有一个降维操作,就是我们在一个r * m(事先以及决定了选取那几行,该去考虑列的问题时)的矩阵中选取c列,这个时候我们可以把二维降低到一维,(因为这其中行已经有了判断的标准,我们只需要进行列的操作就足够了).

下面开始讲DP过程:

我们设f[i][j]表示在这个r*m的矩阵中,在其前i列中选择j列(且选的列中包括第i列),组成的子矩阵中,最小值(即其相邻元素的差的绝对值的和的最小值(之后的值等表达也是指的这个东西,即题目要求求出的值))是多少。

这样,推出状态转移方程如下:

f[i][j] = min (f[k][j-1] + hc[i][k] + lc[i])

下面就都是一些细节上的优化,代码里面已经讲的很清楚了。

Code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,r,c,gs=,minn=0x7fffffff,cmin; //不可能选取0列
int a[][];
int ch[],hc[][],lc[]; //hc[i][j] 对于第i列与第j列之间,所有同一行元素的差的绝对值的和
//lc[i]指的是第i列中所有元素的值
//ch[]是在dfs过程的数组
int f[][];
void init() //初始化
{
for(int i=;i<=m;i++)
{
lc[i] = ;
for(int j=;j<r;j++)
lc[i] += abs(a[ch[j]][i] - a[ch[j + ]][i]); //注意是+=
}
for(int i=;i<=m;i++)
{
for(int j=;j<i;j++) //注意j<i
{
hc[i][j] = ; //注意初始化
for(int k=;k<=r;k++)
hc[i][j] += abs(a[ch[k]][i] - a[ch[k]][j]); //注意是+=
}
}
}
void dp()
{
for(int i=;i<=m;i++)
{
cmin = min(i,c);
for(int j=;j<=cmin;j++)
{
if(j == ) //这个边界是只选取一列,就把元素赋进去就好
f[i][j] = lc[i];
else
if(j == i) //这个边界是前i列都需要选取
f[i][j] = f[i - ][j - ] + lc[i] + hc[i][j - ];
else
{
f[i][j] = 0x7fffffff; //注意初始化
for(int k=j-;k<i;k++)
f[i][j] = min(f[i][j],f[k][j - ] + lc[i] + hc[i][k]); //取最小值
}
if(j == c) //如果这种状态存在,那我们就更新一下
minn = min(minn,f[i][c]);
}
}
}
void dfs(int rt)
{
if(rt > n) //
{
init();
dp();
return ;
}
if(r - gs + == n - rt + ) //敲黑板!
/*
这个地方是一个剪枝,主要优化在了果rt和rt以后的元素必须全部取完,才能满足刚好有r个的条件,
则必须rt,否则便会取到少于r个元素的情况。
这样我们保证了rt > n时所有情况都刚好有r个,
*/
{
ch[gs++] = rt; //注意是gs++而不是++gs
dfs(rt + );
ch[gs--] = ; //注意是gs--而不是--gs
return ;
}
dfs(rt + );
if(gs <= r) //如果已经选取满了
{
ch[gs++] = rt; //但是还是需要这一步
dfs(rt + );
ch[gs--] = ;
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&r,&c);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&a[i][j]); //输入初始矩阵
dfs(); //开始搜索
printf("%d",minn); //答案已经被更新,输出就行
return ;
}

[洛谷P2258][NOIP2014PJ]子矩阵(dfs)(dp)的更多相关文章

  1. 【洛谷P2258】子矩阵

    子矩阵 题目链接 搜索枚举选了哪几行,将DP降为一个一维的问题, 先预处理出w[i]表示该列上下元素差的绝对值之和 v[i][j]为第i列和第j列对应元素之差的绝对值之和 f[i][j]表示前j列中选 ...

  2. 题解 洛谷P2258 【子矩阵】

    应该很容易想到暴力骗分. 我们考虑暴力\(dfs\)枚举所有行的选择,列的选择,每次跑一遍记下分值即可. 时间复杂度:\(O(C_n^r \times C_m^c \times r \times c) ...

  3. 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)

    洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\)​​​​​.我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...

  4. NOIP2014 T4 子矩阵 dfs+dp

    最近在狂补题啊QAQ... 打算先把NOIP的干掉吧... 点我看题 链接还是放洛谷的了... 题意:给一个n*m的矩阵,在这个矩阵里选 r 行 c 列,然后这 r 行 c 列所相交的格子为新矩阵的, ...

  5. 洛谷 P2392 kkksc03考前临时抱佛脚, dp / 深搜

    题目链接 P2392 kkksc03考前临时抱佛脚 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目 dp代码 #include <iostream> #includ ...

  6. 洛谷2344 奶牛抗议(DP+BIT+离散化)

    洛谷2344 奶牛抗议 本题地址:http://www.luogu.org/problem/show?pid=2344 题目背景 Generic Cow Protests, 2011 Feb 题目描述 ...

  7. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  8. 洛谷P1541 乌龟棋(四维DP)

    To 洛谷.1541 乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游 ...

  9. 【洛谷】P1052 过河【DP+路径压缩】

    P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙 ...

随机推荐

  1. Delpher 必记-delphi环境安装

    //Delpher 必记 环境: 安装包: 1.所有第三方控件包放在没有中文名的路径:如F:\DComp 安装包放在对应的版本的文件夹里面(实际中没有分类),然后看安装包的引用路径和输出路径,都要设定 ...

  2. JSON和JSONP的区别,以及使用方法

    (一)场景 在拉京东城市选择的基础数据时候,遇到被服务器拒绝的情况,也就是ajax跨域问题 (二)json和jsonp 说的直白一点,在我们做ajax异步的一些功能的时候,一定会或多或少的遇到两个问题 ...

  3. JXL读取Excel(只支持xls版本)——(二)

    注意:jxl是不支持xlsx后缀的excel的.因此建议用POI读取excel. Jar包 同一一样 Java代码 package JXL; import java.io.File; import j ...

  4. WPF复制异常问题(OpenClipboard 失败 (异常来自 HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN)))

    最近在维护WPF系统的时候发现的问题,刚刚开始自己的电脑都不能重现,后面写日志跟踪才发现问题的所在.问题主要是由于:1.   在程序访问剪切板的时候,有其他程序正在占用剪切板,导致自己的程序无法访问, ...

  5. UML和模式应用5:细化阶段(2)--细化阶段制品之领域模型

    1.前言 领域模型是OO分析中最重要和经典的模型.它阐述了领域中的重要概念: 领域模型作为设计某些软件对象的重要来源,也作为案例研究中探讨的几个制品的输入: 领域模型的范围限定于当前迭代开发的用例场景 ...

  6. Oracle11g的database 和client的区别是什么?

    由于工作需要,刚开始接触oracle数据库,完全小白,下载的时候看到有database和client两种类型可供下载,一时不知如何是好,于是网上询问得知其中区别,在此记录一下自己的无知. “datab ...

  7. Android:自定义Dialog

    自定义Dialog:显示SeekBar 效果图: 步骤: //SettingActivity.java button4.setOnClickListener(new View.OnClickListe ...

  8. [Java]求文件大小并保留两位小数(文件大小是一个长整型数单位是Byte)

    前言 为了获得一堆apk的大小,并与人类友好方式显示.本来是打算用以下方法,到时不能具体到保留两位小数. org.apache.commons.io.FileUtils.byteCountToDisp ...

  9. javascript NaN注意事项

    NaN直译是Not a number NaN是个特殊的number,它和任何值相比都不相等,甚至和它自己. NaN === NaN 这个表达式是false 唯一能判断NaN的方法是 IsNaN(NaN ...

  10. java 语言的主要特点

    java 语言主要特点如下: 1:简单 2:面向对象 3:分布性 4:可移植性 5:安全性 6:健壮性 二:java 主要术语 三:java 核心是面向对象程序设计OOP 四:封装 五:多态 六:继承 ...