• bzoj 1084: [SCOI2005]最大子矩阵


    Description
    这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵
    不能相互重叠。
    Input
    第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的
    分值的绝对值不超过32767)。
    Output
    只有一行为k个子矩阵分值之和最大为多少。
    Sample Input
    3 2 2
    1 -3
    2 3
    -2 3
    Sample Output
    9

    解题报告:这数据范围就看出是个SBT,但本人太菜,写的又丑又长,复杂度又高.
    定义f[i][j][k]表示第一列的前i列第二行的前j列都处理完,一共选出了k个的最大分值之和,这个显然是很好转移的:枚举矩阵大小和形状,然后分情况转移即可
    复杂度(O(n^3k))

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=105,inf=2e8;
    int f[N][N][15],a[N][3],g[3][N][N],xy[N][N];
    void work()
    {
    	int n,m,K;
    	scanf("%d%d%d",&n,&m,&K);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			scanf("%d",&a[i][j]);
    	for(int j=1;j<=2;j++){
    		//g[j][i][k]表示第j列的i-k一段的最大子段和
    		for(int i=1;i<=n;i++){
    			for(int k=1;k<=i;k++){
    				int tot=0,ret=-inf;
    				for(int l=i;l>=k;l--){
    					if(tot<0)tot=a[l][j];
    					else tot+=a[l][j];
    					if(tot>ret)ret=tot;
    				}
    				g[j][k][i]=ret;
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		//xy[i][j]表示前两列一起时 i-j的最大子段和
    		for(int k=1;k<=i;k++){
    			int tot=0,ret=-inf;
    			for(int l=i;l>=k;l--){
    				if(tot<0)tot=a[l][1]+a[l][2];
    				else tot+=a[l][1]+a[l][2];
    				if(tot>ret)ret=tot;
    			}
    			xy[k][i]=ret;
    		}
    	}
    	int s,ans=-inf;
    	for(int k=0;k<K;k++)
    		for(int i=0;i<=n;i++){
    			for(int j=0;j<=n;j++){
    				f[i][j][k+1]=Max(f[i][j][k+1],f[i][j][k]);
     				s=Max(i,j)+1;
    				for(int l=s;l<=n;l++){
    					f[l][l][k+1]=Max(f[l][l][k+1],f[i][j][k]+xy[s][l]);
    				}
    				for(int l=i+1;l<=n;l++)
    					f[l][j][k+1]=Max(f[l][j][k+1],f[i][j][k]+g[1][i+1][l]);
    				for(int l=j+1;l<=n;l++)
    					f[i][l][k+1]=Max(f[i][l][k+1],f[i][j][k]+g[2][j+1][l]);
    			}
    		}
    	for(int i=0;i<=n;i++)
    		for(int j=0;j<=n;j++)
    			ans=Max(ans,f[i][j][K]);
    	printf("%d
    ",ans);
    }
    int main()
    {
    	freopen("pp.in","r",stdin);
    	freopen("pp.out","w",stdout);
     	work();
    	return 0;
    }
    
  • 相关阅读:
    数据结构之单链表的实现java
    从尾到头打印列表——牛客剑指offer
    Java重要类之LinkedList
    删除链表中重复的结点——牛客剑指offer
    二维数组中的查找——牛客剑指offer
    爬虫常见异常
    持续集成常见异常及排除方案
    VMware安装与基本使用
    web开发常见异常及处理
    Linux简单介绍与基本使用(微系统,)
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7481841.html
Copyright © 2020-2023  润新知