• bzoj 1084 最大子矩阵


    Written with StackEdit.

    Description

    这里有一个(n*m)的矩阵,请你选出其中(k)个子矩阵,使得这个(k)个子矩阵分值之和最大.注意:选出的(k)个子矩阵不能相互重叠。

    ps:这里的题意有些不明确...可以选空矩阵(最多选(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

    Hint

    none.

    Solution

    • 注意到只有(m=1,m=2)两种情况.
      • 对于(m=1)的情况,直接做一个最大字段和(dp)就可以了.
      • (f[i][j][0/1])表示考虑前(i)个数,用了(j)段,第(i)个数选了/没选的答案.
    • 对于(m=2)的情况,与(m=1)类似,用(f[i][j][k])表示考虑前(i)个数,用了(j)个矩形,而(k)用于表示第(i)行的选择情况.
    • 不妨令(k=0)表示这一行都没选.
    • (k=1)表示这一行只选了左边的数.
    • (k=2)表示这一行只选了右边的数.
    • 对于左右两个数都选的情况,注意到样例中第二行的(2,3)虽然同时被选到,但属于不同的子矩形,所以要对是否在同一个子矩形中进行区分.
    • (k=3)表示这一行同时选了左右两个数,且两个数属于相同的子矩形
    • (k=4)表示这一行同时选了左右两个数,且两个数属于不同的子矩形.
    • 在转移时分别判断能否和上一行的各个状态拼接上,就完成了状态转移.
    • 这样我们也不用特判(m)了,将(m=1)的时候看做第二列都是(0),一起处理.
    • 具体转移方程和细节参见代码.
    #include<bits/stdc++.h> 
    using namespace std;
    inline int read()
    {
    	int out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		{
    			fh=-1;
    			jp=getchar();
    		}
    	while (jp>='0'&&jp<='9')
    		{
    			out=out*10+jp-'0';
    			jp=getchar();
    		}
    	return out*fh;
    }
    int n,m,k;
    const int MAXN=101;
    int a[MAXN][2];
    int f[MAXN][11][5];
    inline void upd(int &x,int y)
    {
    	x=max(x,y);
    }
    void sub_line()
    {
    	int ans=0;
    	for(int i=1;i<=n;++i)
    		{
    			for(int j=1;j<=k;++j)
    				{
    					f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
    					f[i][j][1]=max(f[i-1][j-1][0]+a[i][1],f[i-1][j][1]+a[i][1]);
    					upd(ans,f[i][j][0]);
    					upd(ans,f[i][j][1]);
    				}
    		}
    	printf("%d
    ",ans);
    }
    void sub_martix()
    {
    	int ans=0;
    	memset(f,-0x7f,sizeof f);//一定要加上这句话,否则有些矩阵当前权值和为负,为了和其他部分凑成矩形必须选上.
    	f[0][0][0]=0;
    	for(int i=1;i<=n;++i)
    		{
    			int x=a[i][1],y=a[i][2];
    			upd(f[i][0][0],f[i-1][0][0]);
    			for(int j=1;j<=k;++j)
    				{
    					for(int p=0;p<5;++p)//last
    						upd(f[i][j][0],f[i-1][j][p]);
    					upd(f[i][j][1],f[i-1][j-1][0]+x);
    					upd(f[i][j][1],f[i-1][j][1]+x);
    					upd(f[i][j][1],f[i-1][j-1][2]+x);
    					upd(f[i][j][1],f[i-1][j-1][3]+x);
    					upd(f[i][j][1],f[i-1][j][4]+x);
    					
    					upd(f[i][j][2],f[i-1][j-1][0]+y);
    					upd(f[i][j][2],f[i-1][j-1][1]+y);
    					upd(f[i][j][2],f[i-1][j][2]+y);
    					upd(f[i][j][2],f[i-1][j-1][3]+y);
    					upd(f[i][j][2],f[i-1][j][4]+y);
    					
    					upd(f[i][j][3],f[i-1][j-1][0]+x+y);
    					upd(f[i][j][3],f[i-1][j-1][1]+x+y);
    					upd(f[i][j][3],f[i-1][j-1][2]+x+y);
    					upd(f[i][j][3],f[i-1][j][3]+x+y);
    					upd(f[i][j][3],f[i-1][j-1][4]+x+y); 
    					
    					if(j>=2)
    						upd(f[i][j][4],f[i-1][j-2][4]+x+y);
    					if(j>=2)
    						upd(f[i][j][4],f[i-1][j-2][0]+x+y);
    					upd(f[i][j][4],f[i-1][j-1][1]+x+y);
    					upd(f[i][j][4],f[i-1][j-1][2]+x+y);
    					upd(f[i][j][4],f[i-1][j][4]+x+y);
    					
    					upd(ans,f[i][j][0]);
    					upd(ans,f[i][j][1]);
    					upd(ans,f[i][j][2]);
    					upd(ans,f[i][j][3]);
    					upd(ans,f[i][j][4]);
    				}
    		}
    	printf("%d
    ",ans);
    }
    int main()
    {
    	n=read(),m=read(),k=read();
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			a[i][j]=read();
    	/*if(m==2)
    		sub_martix();
    	else
    		sub_line();*/
    	sub_martix();
    	return 0;
    }
    
  • 相关阅读:
    Java annotation
    子类 父类强转 HttpServlet service实现
    父类 子类 强转
    HttpServlet Service方法
    java go
    IO写 PrintWriter
    IO读 BufferedReader+FileReader
    Java NIO-3
    心跳包(HeartBeat)
    Git学习笔记(一)
  • 原文地址:https://www.cnblogs.com/jklover/p/9996092.html
Copyright © 2020-2023  润新知