/*
推荐题型:四星。 动态规划
题意:输入矩形长度N,矩形中节点上的数值A[i][j],输出子矩形所包含节点的数值之和的最大值。
动态规划策略:
状态:d[lx][ly][rx][ry]表示矩形(lx,ly,rx,ry)中的最大值。
状态转移方程:d[lx][ly][rx][ry]=max(d[lx+1][ly][rx][ry],d[lx][ly+1][rx][ry],d[lx][ly][rx-1][ry],d[lx][ly][rx][ry-1],All()) //其中All()表示矩形中所有节点之和。结果超时,效率为O(N*N*N*N)
看别人代码后,分阶段进行动态规划,行数逐渐增加,可以定一个状态(设最大行数为k,且子矩形下边必为k),然后历编子矩形上边i,这两个状态确定后,对列进行判断,使用数组d[j]表示右边为j的最大值,这样只需搜索一遍就可以找到,上下边确立后子矩形的最大值。可讲效率缩小到O(N*N*N)
主要改进:使用了中间状态,确立矩形的下边,右边,从而提高效率,不过还不会用。。。
*/
#include <cstdio>
#include <cstring>
const int nMax=107;
const int INF=0x7fffffff;
int A[nMax][nMax];
int sum[nMax][nMax];
int d[nMax][nMax][nMax][nMax];
int N;
void init()
{
scanf("%d", &N);
int i, j;
for(i = 1; i <= N; ++ i)
{
sum[i][0] = 0;
for(j = 1; j <= N; ++ j)
{
scanf("%d", &A[i][j]);
sum[i][j] = sum[i][j-1] + A[i][j];
}
}
}
int max(int a,int b)
{
return a > b ? a : b;
}
/*int dp(int lx, int ly, int rx, int ry)
//递归实现
{
if(lx > rx || ly > ry) return -INF;
int &temp = d[lx][ly][rx][ry];
if(temp != -1) return temp;
temp = -INF;
temp=max(temp,dp(lx+1,ly,rx,ry));
temp=max(temp,dp(lx,ly+1,rx,ry));
temp=max(temp,dp(lx,ly,rx-1,ry));
temp=max(temp,dp(lx,ly,rx,ry-1));
int c=0;
for(int i=lx;i<=rx;i++)
c+=sum[i][ry]-sum[i][ly-1];
temp=max(temp,c);
return temp;
}*/
void dp()
//非递归实现,仍然超时。
{
int kx,ky,x,y;
for(kx = 0; kx < N; ++ kx)//行的增量
for(ky = 0; ky < N; ++ ky)//列的增量
{
for(x = 1; x + kx <= N; ++ x)//子矩形左上角坐标
for(y = 1; y + ky <= N;++ y)
{
if(0 == kx)
{
d[x][y][x+kx][y+ky] = sum[x][y+ky] - sum[x][y-1];
}
else if(0 == ky)
{
int a = 0;
for(int i = x; i <= x + kx; ++ i)
a += A[i][y];
d[x][y][x+kx][y+ky] = a;
}
else
{
int max1 = -INF;
max1 = max(max1, d[x+1][y][x+kx][y+ky]);
max1 = max(max1, d[x][y+1][x+kx][y+ky]);
max1 = max(max1, d[x][y][x+kx-1][y+ky]);
max1 = max(max1, d[x][y][x+kx][y+ky-1]);
int c=0;
for(int i = x;i <= x + kx;i++)
c+=sum[i][y + ky]-sum[i][y-1];
max1 = max(max1, c);
d[x][y][x+kx][y+ky] = max1;
}
}
}
}
int main()
{
//freopen("f://data.in","r",stdin);
init();
//dp(1, 1, N, N);
dp();
printf("%d\n",d[1][1][N][N]);
return 0;
}
//方法二:改进后的动态规划
#include <cstdio>
#include <cstring>
const int nMax=107;
const int INF=0x7fffffff;
int A[nMax][nMax];
int N;
int ans;
void init()
{
scanf("%d", &N);
int i, j;
for(i = 1; i <= N; ++ i)
for(j = 1; j <= N; ++ j)
scanf("%d", &A[i][j]);
ans = -INF;
}
int max(int a,int b)
{
return a > b ? a : b;
}
void dp(int k)
{
int a[nMax],d[nMax];
memset(a,0,sizeof(a));
memset(d,0,sizeof(d));
for(int i = k; i >= 1; -- i)
for(int j = 1; j <= N; ++ j)
{
a[j] += A[i][j];
d[j] = max(d[j-1] + a[j], a[j]);
if(d[j] > ans)
ans = d[j];
}
}
int main()
{
//freopen("f://data.in","r",stdin);
init();
for(int i = 1; i <= N; ++ i)
dp(i);
printf("%d\n",ans);
return 0;
}
108 Maximum Sum
最新推荐文章于 2024-05-26 21:18:43 发布