P2258 子矩阵——搜索+dp

P2258 子矩阵

二进制枚举套二进制枚举能过多一半的点;

我们只需要优化一下第二个二进制枚举的部分;

首先我们先枚举选哪几行,再预处理我们需要的差值,上下,左右;

sum_shang,sum_heng

然后DP查找最小值

dp[i][j]表示前i列已经选了j列;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20;
int n,m,r,c;
int a[maxn][maxn];
int id[maxn];
int b[maxn];
int sum_s[maxn];
int sum_h[maxn][maxn];

void pre_pare()
{
    memset(sum_s,0,sizeof(sum_s));
    int num=0;
    for(int i=1;i<=n;i++) if(b[i]) id[++num]=i;
    for(int i=1;i<r;i++)
    {
        for(int j=1;j<=m;j++)
        {
            sum_s[j]+=abs(a[id[i]][j]-a[id[i+1]][j]);
        }
    }

    for(int i=1;i<=m;i++)
    {
        for(int j=i+1;j<=m;j++)
        {
            sum_h[i][j]=0;
            for(int k=1;k<=r;k++)
            {
                sum_h[i][j]+=abs(a[id[k]][i]-a[id[k]][j]);
            }
        }
    }

}

int ans=2147483647,res=2147483647;
int dp[maxn][maxn];

int query()
{
    memset(dp,0x3f,sizeof(dp));
    res=2147483647;
    for(int i=1;i<=m;i++)
    {
        dp[i][1]=sum_s[i];
        for(int j=2;j<=c;j++)
        {
            for(int k=1;k<i;k++)
            {
                dp[i][j]=min(dp[i][j],dp[k][j-1]+sum_s[i]+sum_h[k][i]);
            }
        }
        res=min(res,dp[i][c]);
    }
    return res;
}

void dfs(int x,int sum)
{
    if(sum>r) return ;
    if(x==n+1)
    {
        if(sum!=r) return ;
        pre_pare();
        ans=min(ans,query());
        return ;
    }
    b[x]=0;
    dfs(x+1,sum);
    b[x]=1;
    dfs(x+1,sum+1);
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&r,&c);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    dfs(1,0);
    printf("%d",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/WHFF521/p/11675228.html

时间: 2024-10-21 05:14:52

P2258 子矩阵——搜索+dp的相关文章

hdu 4960 记忆化搜索 DP

Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 490    Accepted Submission(s): 180 Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morni

NOIP2014pj子矩阵[搜索|DP]

题目描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵. 例如,下面左图中选取第2.4行和第2.4.5列交叉位置的元素得到一个2*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*3的子矩阵是 4 7 4 8 6 9 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的. 矩阵的分值:矩阵中每一对相邻元素之差

【Luogu】P2258子矩阵(状态压缩,DP)

233今天蒟蒻我连文化课都没听光想着这个了 然后我调了一下午终于过了!!! 一看数据范围似乎是状压,然而216等于65536.开一个65536*65536的二维数组似乎不太现实. 所以Rqy在四月还是几月给我们讲这道题的时候说要半DFS半DP,时间复杂度O(2n*n3) 怎么个半DFS半DP法呢? 其实我没DFS.所以这个问题不重要. 我真的没用DFS.枚举从1到2n-1的所有集合,把二进制数中1的个数不等于r的都筛掉.然后对于每个状态,预处理出每一列内部的代价,预处理出列与列之间的代价,然后进

P2258 子矩阵

题目描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵. 例如,下面左图中选取第2.4行和第2.4.5列交叉位置的元素得到一个2*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*3的子矩阵是 4 7 4 8 6 9 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的. 矩阵的分值:矩阵中每一对相邻元素之差

HDU 1078 FatMouse and Cheese(记忆化搜索DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078 题目大意:一个n*n的图,每个点都有奶酪,老鼠从(0,0)开始走,每次最多只能走k步就要停下来,停下的这个位置的奶酪数只能比上一个停留的位置大,并获取其奶酪,每次只能水平或垂直走,问最多能得到的奶酪. 解题思路:记忆化搜索,这方面还是写的太少,还要看别人才会,这个就当个例子参考吧. 1 #include<cstdio> 2 #include<cstring> 3 #include

记忆化搜索(搜索+dp思想)

一:简介 (1)记忆化搜索 即 搜索+动态规划数组记录上一层计算结果,避免过多的重复计算 算法上依然是搜索的流程,但是搜索到的一些解用动态规划的那种思想和模式作一些保存:一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态.更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多. 记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,以后再次遇到这个状态的时候,就不必重新求解了. 这种方法综合了搜索和动态规划两方面的

记忆化搜索+dp(洛谷1514 引水入城2010noip提高组)

在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送.故一座城市能建造输水站

NOIP1999邮票面值设计[搜索|DP]

题目描述 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1-MAX之间的每一个邮资值都能得到. 例如,N=3,K=2,如果面值分别为1分.4分,则在1分-6分之间的每一个邮资值都能得到(当然还有8分.9分和12分):如果面值分别为1分.3分,则在1分-7分之间的每一个邮资值都能得到.可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分.3分. 输入

hdu1331&amp;&amp;hdu1579记忆化搜索(DP+DFS)

这两题是一模一样的``` 题意:给了一系列递推关系,但是由于这些递推很复杂,所以递推起来要花费很长的时间,所以我要编程序在有限的时间内输出答案. w(a, b, c): 如果a,b,c中有一个值小于等于0,那么w(a, b, c)的值为1 如果a,b,c中有一个值大于20,那么w(a, b, c)的值为w(20, 20, 20) 如果a<b<c,那么w(a, b, c)=w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c) 否则w(a, b, c)=w(a-