zoukankan      html  css  js  c++  java
  • 子矩阵

    洛咕

    题意:给出如下定义:

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

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

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

    本题任务:给定一个(n)(m)列的正整数矩阵,请你从这个矩阵中选出一个(r)(c)列的子矩阵,使得这个子矩阵的分值最小,并输出这个分值.

    (n,m<=16.)

    分析:直接暴力枚举出所有的行的组成情况,然后用(DP)求出选哪些列能够使得分值最小.设(f[i][j])表示从前i列中一共选了j列且选了第i列的最小分值,(dis[i])表示第i列的分值(在已知选哪些行的情况下),(dist[i][j])表示第i列与第j列产生的分值(在已知选哪些行的情况下),则(f[i][j]=f[k][j-1]+dist[k][i]+dis[i].)

    在每次选完行之后,(DP)列之前,显然(dis,dist)两个数组都是可以预处理的.

    时间复杂度应该是(C_n^r*m^3).反正能过.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=20;
    int n,m,r,c,ans=1e9;
    int bj[N],a[N],dis[N];
    int jz[N][N],dist[N][N],f[N][N];
    inline void dp(){
    	memset(dis,0,sizeof(dis));
    	memset(dist,0,sizeof(dist));
    	memset(f,0x3f,sizeof(f));//初始化
    	for(int j=1;j<=m;++j)
    		for(int i=1;i<r;++i)
    			dis[j]+=abs(jz[a[i]][j]-jz[a[i+1]][j]);
    	for(int j=1;j<m;++j)
    		for(int k=j+1;k<=m;++k)
    			for(int i=1;i<=r;++i)
    				dist[j][k]+=abs(jz[a[i]][j]-jz[a[i]][k]);	
    	for(int i=1;i<=m;++i)f[i][1]=dis[i];
    	for(int i=1;i<=m;++i)
    		for(int j=2;j<=min(i,c);++j)
    			for(int k=j-1;k<=i-1;++k)
    				f[i][j]=min(f[i][j],f[k][j-1]+dist[k][i]+dis[i]);
    	for(int i=c;i<=m;++i)ans=min(ans,f[i][c]);
    }
    inline void dfs(int now){//搜索枚举所有的行的组成情况
    	if(now>r){dp();return;}//选完了之后就去dp列的情况
    	for(int i=1;i<=n;++i)
    		if(!bj[i]&&a[now-1]<i){//保证选出的行是递增的,也算是避免重复搜索状态
    			bj[i]=1;
    			a[now]=i;
    			dfs(now+1);
    			bj[i]=0;
    		}
    }
    int main(){
    	n=read();m=read();r=read();c=read();
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			jz[i][j]=read();
    	dfs(1);printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    ps-- 制作磨砂背景
    ps -- 证件照
    抠图--薄,透
    60后发送短信的方法
    小项目 -- 验证码.js
    小项目
    小项目 -- phone.js
    基于GDAL提取地物,并生成png,最后加载到网页上(二)
    根据范围获取影像瓦片,并生成GeoTIFF 文件《一》
    Ubuntu 10.4 +NVIDIA GTX 1070 显卡驱动更新
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11617687.html
Copyright © 2011-2022 走看看