【前言】
°朱老湿上次提了一句这个,其实挺水的,但还算挺经典的吧。简略说说接着刷题去…
【最大连续字段和】
°Problem:对{an}数列,求最大的一段子序列的和。
°Solution:F[i]←max{F[i-1]+a[i],a[i]}(1<=i<=n)
°Answer:Max{F[i]}(1<=i<=n)
°Code:
1: Program Max_1(input,output);2: var n,i,ans:Longint;
3: F,a:array[0..100]of longint;4: function max(a,b:Longint):Longint;
5: begin
6: if a>b then exit(a) else exit(b);7: end;
8: begin
9: readln(n);10: for i:=1 to n do read(a[i]);ans:=-19940805;11: for i:=1 to n do12: begin
13: F[i]:=max(F[i-1]+a[i],a[i]);14: if ans<F[i] then ans:=F[i];15: end;
16: writeln(ans);17: end.
°Extended:在一个长度为n的数列{An}中,求m个连续子序列,使得这m个连续子序列的和最大,且m个子序列无公共元素。
°Solution:解决类似的问题,我们可以利用“加一维”的思想利用动态规划来解决。
F[i,j]表示数列前j个元素中,i个无公共元素的子序列的最大和,且必须包含第j个元素。
F[i,j]=max{F[i,j-1]+a[j](i<=j<=n),F[i-1,k]+a[j](i-1<=k<=j-1)}
时间复杂度为O(n^3)
°Code:
1: Program Max_2(input,output);2: var n,m,ans,i,j,k:longint;
3: a:array[1..100]of longint;4: F:array[0..100,0..100]of longint;5: Function max(a,b:longint):longint;6: begin
7: if a>b then exit(a) else exit(b);8: end;
9: begin
10: readln(n,m);11: for i:=1 to n do read(a[i]);12: for i:=1 to m do13: for j:=i to n do14: begin
15: F[i,j]:=F[i,j-1]+a[j];16: for k:=i-1 to j-1 do17: F[i,j]:=max(F[i-1,k]+a[j],F[i,j]);18: end;
19: ans:=-19940805;20: for i:=1 to n do21: if F[m,i]>ans then ans:=F[m,i];22: writeln(ans);23: end.
【最优子矩阵】
°Problem:对n×m的矩阵,求最大的一个子矩阵的和。
°Solution:枚举边界,将矩阵压缩成线性,用最大字段和出解
°Code:
1: Program Max_Matrix(input,output);2: var a:array[1..100,1..100]of longint;3: aa,F:array[1..100]of longint;4: i,j,n,m,up,down,ans:longint;5: Function max(a,b:longint):Longint;6: begin
7: if a>b then exit(a) else exit(b);8: end;
9: Procedure Zip(up,down:longint);10: begin
11: fillchar(aa,sizeof(aa),0);12: for i:=1 to m do13: for j:=up to down do14: inc(aa[i],a[i,j]);15: end;
16: begin
17: readln(n,m);18: for i:=1 to n do19: for j:=1 to m do20: read(a[i,j]);21: ans:=-19940805;22: for up:=1 to n do23: for down:=1 to n do24: begin
25: Zip(up,down);26: fillchar(F,sizeof(F),0);27: for i:=1 to m do28: begin
29: F[i]:=max(F[i-1]+aa[i],aa[i]);30: if F[i]>ans then ans:=F[i];31: end;
32: end;
33: writeln(ans);34: end.
°Extended:在一个n*m二维的矩阵中,确定两个小的矩阵,使这两个小矩阵中所有元素的总和最大,且两个矩阵无公共元素。
这个不会…真心复杂…分类讨论+枚举伤不起
【例题】
°Vijos 1057 House Building(这个不是最优子矩阵,但是很有趣啊~呵呵)
描述 Description有面积为n*m的一大块土地,要在这块土地上建造一所房子,这个房子必须是正方形的。但是,这块土地上面有很多不平坦的地方,这些地方不能用来盖房子。他希望找到一块最大的正方形来盖房子。输入格式 Input Format输入文件第一行为两个整数n,m(1<=n,m<=1000)接下来n行,每行m个数字,用空格隔开。0表示该块土地不平坦,1表示该块土地完好。输出格式 Output Format一个整数,最大正方形的边长。样例输入 Sample Input4 40 1 1 11 1 1 00 1 1 01 1 0 1样例输出 Sample Output2
°Solution:F[i,j]表示以(i,j)为右下角的最大正方形的边长。
F[i,j]←min{F[i-1,j],F[i,j-1],F[i-1,j-1]}+1
注意方程要取min:
***************
***************
***************
***************
我们设f[i-1, j]=3,首先我们可以保证红色区域为1,再设f[I,j-1]=2 那么绿色区域为1
***************
***************
***************
***************
我们设f[i-1, j-1]=3,那么蓝色区域为1.
***************
***************
***************
***************
很明显,我们应该选取最小值,才可以确定以(I,j)为右下角的最大正方形长度。
这是一个经典的由方案合理性确定opt的问题。
°Code:
Program HouseBuilding(input,output);var F,a:array[0..1000,0..1000]of integer;n,m,i,j,ans:integer;Function min(a,b,c:integer):integer;begin
min:=a;if b<min then min:=b;if c<min then min:=c;end;
begin
readln(n,m);for i:=1 to n dofor j:=1 to m doread(a[i,j]);ans:=-19940805;for i:=1 to n dofor j:=1 to m doif a[i,j]=1 thenbegin
F[i,j]:=min(F[i-1,j],F[i,j-1],F[i-1,j-1])+1;if F[i,j]>ans then ans:=F[i,j];end;
writeln(ans);end.
°Strengthed House Building(可行性最优子矩阵)
描述 Descriptionn*m的矩形,有的位置被禁止选取,可以选取的格子价值不同。找出一个最大的 矩形平地,使得这个矩形合法且价值最大。输入 Input从文件读入数据。第一行有两个整数n,m。第i+1行的第j个数表示a[i][j].如果这个数为0,则表示这个位置的格子被禁止。1≤n,m≤1000 0≤a[i][j]≤255 保证输入数据都是整数。输出 Output最大的利用价值。输入样例3 41 2 3 45 0 6 310 3 4 0输出样例17
°地精工程师(价值可变最优子矩阵)
【跋】
没啥说的,就这样吧