• [NOIP2014普及组]子矩阵


    题目:洛谷P2258、Vijos P1914、codevs 3904。

    题目大意:给你一个矩阵,要你找一个r行c列的子矩阵,求最小分值(子矩阵和分值的定义见原题)。

    解题思路:n和m比较小,考虑暴力。

    发现时间复杂度为$O(C_n^r ×C_m^c)$,可能会炸掉。因此考虑优化。

    我们可以只暴力出行,然后通过dp求出和:

    设f[i][j]表示选i列最后一个选j所得到的最小分值,x[i][j]表示第i列和第j列能产生的分值(不包括上下),y[i]表示第i列能产生出的分值(上下),这些都表示当前暴力到的状态。

    则$f[i][j]=f[i-1][k]+y[j]+x[k][j](2leq ileq c,ileq jleq m,i-1leq kleq j-1)$,边界f[1][i]=y[i]。

    最后答案为$min(f[c][i])(cleq ileq m)$。

    dp时间复杂度是$O(m^3)$的,那么总时间复杂度优化到$O(C_n^r × m^3)$。

    C++ Code:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #define For(i,a,b) for(register int i=a;i<=b;++i)
    #define min(a,b) (((a)<(b))?(a):(b))
    int a[17][17],n,m,r,c,num[17],ans,f[17][17],y[17],x[17][17];
    void dp(){
    	memset(f,0x3f,sizeof f);
    	memset(f[1],0,sizeof f[1]);
    	memset(y,0,sizeof y);
    	memset(x,0,sizeof x);
    	For(i,1,m)For(j,2,r)
    	y[i]+=abs(a[num[j]][i]-a[num[j-1]][i]);
    	For(i,1,m)
    	For(j,i+1,m)
    	For(k,1,r)
    	x[i][j]+=abs(a[num[k]][i]-a[num[k]][j]);
    	memcpy(f[1],y,sizeof f[1]);
    	For(i,2,c)
    	For(j,i,m)
    	For(k,i-1,j-1)
    	f[i][j]=min(f[i][j],f[i-1][k]+y[j]+x[k][j]);
    	For(i,c,m)ans=min(ans,f[c][i]);
    }
    void dfs(int now){
    	if(now>r){
    		dp();
    		return;
    	}
    	For(i,num[now-1]+1,n){
    		num[now]=i;
    		dfs(now+1);
    	}
    }
    int main(){
    	ans=0x3f3f3f3f;
    	scanf("%d%d%d%d",&n,&m,&r,&c);
    	For(i,1,n)For(j,1,m)
    	scanf("%d",&a[i][j]);
    	num[0]=0;
    	dfs(1);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    第九周学习报告
    人月神话阅读笔记02
    数组 分步 详细
    第八周学习总结
    课堂练习
    学习进度报告09
    用户模板和用户场景
    学习进度报告08
    课堂随笔
    学习进度报告07
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7694233.html
Copyright © 2020-2023  润新知