2017ACM北京网络赛-HihoCode-1580-C-Matrix-dp

2017ACM北京网络赛-HihoCode-1580-C-Matrix-dp

Description

Once upon a time, there was a little dog YK. One day, he went to an antique shop 
and was impressed by a beautiful picture. YK loved it very much.

However, YK did not have money to buy it. He begged the shopkeeper whether he could 
have it without spending money.

Fortunately, the shopkeeper enjoyed puzzle game. So he drew a n × m matrix on the
paper with integer value ai,j in each cell. He wanted to find 4 numbers x, y, x2,
and y2(x ≤ x2, y ≤ y2), so that the sum of values in the sub-matrix from (x, y) to 
(x2, y2) would be the largest.

To make it more interesting, the shopkeeper ordered YK to change exactly one cell's 
value into P, then to solve the puzzle game. (That means, YK must change one cell's
value into P.)

If YK could come up with the correct answer, the shopkeeper would give the picture
to YK as a prize.

    YK needed your help to find the maximum sum among all possible choices.

Input

    There are multiple test cases.

    The first line of each case contains three integers n, m and P. 
    (1 ≤ n, m ≤ 300, -1000 ≤ P ≤ 1000).

    Then next n lines, each line contains m integers, which means ai,j (-1000 ≤ ai,j ≤ 1000).

Output

For each test, you should output the maximum sum.

Examples

Input

3 3 4
-100 4 4
4 -10 4
4 4 4
3 3 -1
-2 -2 -2
-2 -2 -2
-2 -2 -2

Output

24
-1

Problem Description

最大子矩阵和变形。
求最大子矩阵和的基础上,可以修改任意一个位置,将其值改为p(必须修改一次)

Solution

类似求最大子矩阵和。dp。
定义dp数组,dp[i][0]表示前i列,不修改任何点的最大值。dp[i][1]表示前i列,修改其中一个点的最大值.
mval[k],保存[i,j]行,第k列的最小值
则可写出状态转移方程
dp[i][0]=max(dp[i-1][0],(int)0)+sum[i];//基础的最大子矩阵和方程
dp[i][1]=max(max(dp[i-1][1]+sum[i],(int)0+sum[i]-mval[i]+p),dp[i][0]-mval[i]+p);
第二个方程解释一下:
当前状态可以从三个状态转移过来。
dp[i-1][1]+sum[i],就是如果已经有一个点修改过并且大于0,后面就直接当求最大子矩阵和一样求就好了。
0+sum[i]-mval[i]+p,如果前面已经修改过,但是和小于0,则需重新修改并求和。
dp[i][0]-mval[i]+p,如果前面没有修改,则修改后求和
需要特判如果最大子矩阵就是矩阵本身的情况。具体看Code。
不知道怎么求最大子矩阵和的建议先去学一下。下面贴个自己的博客链接。

—————————————————- 最大子矩阵和


Code

/*
 * @Author: Simon 
 * @Date: 2018-08-25 09:14:15 
 * @Last Modified by: Simon
 * @Last Modified time: 2018-08-25 18:50:15
 */
#include<bits/stdc++.h>
using namespace std;
typedef int Int;
#define int long long
#define INF 0x3f3f3f3f
#define maxn 1005
int dp[maxn][2];//dp[i][0]表示前i列,不修改任何点的最大值。dp[i][1]表示前i列,修改其中一个点的最大值
int a[maxn][maxn];
int mval[maxn];//保存[i,j]行,第k列的最小值
int sum[maxn];//保存[i,j]行,第k列的和
int solve(int r1,int r,int c,int p,int n)
{
    for(int i=1;i<=c;i++)
    {
        sum[i]+=a[r][i];
        mval[i]=min(mval[i],a[r][i]);
    }
    memset(dp,-INF,sizeof(dp));//必须初始化为无穷小---
    int ans=-INF,flag=1;//flag用于标记最大值是否是整个矩阵,flag=1则是,否则不是
    for(int i=1;i<=c;i++)
    {
        if(dp[i-1][0]<0) flag=i;
        dp[i][0]=max(dp[i-1][0],(int)0)+sum[i];
        dp[i][1]=max(max(dp[i-1][1]+sum[i],(int)0+sum[i]-mval[i]+p),dp[i][0]-mval[i]+p);//如果前一个值是修改过的值,直接加上当前列,否则需要修改一个值
        if(r1==1&&r==n&&i==c&&flag==1) ans=max(ans,dp[i][1]);//如果是整个矩阵的和,必须要修改一个
        else ans=max(ans,max(dp[i][0],dp[i][1]));//如果子矩阵,最大子矩阵内可以不修改
    }
    return ans;
}
Int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,p;
    while(cin>>n>>m>>p)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>a[i][j];
        int ans=-INF;
        for(int r1=1;r1<=n;r1++)
        {
            memset(mval,INF,sizeof(mval));
            memset(sum,0,sizeof(sum));
            for(int r2=r1;r2<=n;r2++)
            {
                ans=max(ans,solve(r1,r2,m,p,n));
            }
        }
        cout<<ans<<endl;
    }
    cin.get(),cin.get();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值