https://www.luogu.com.cn/problem/solution/P2380
题解:因为只能走直线,不能拐弯,所以若
(
i
,
j
)
(i,j)
(i,j)想去左边,那么
(
i
,
j
−
1
)
,
(
i
,
j
−
2
)
.
.
.
.
.
.
(i,j-1),(i,j-2)......
(i,j−1),(i,j−2)......都得去左边,上边同理。设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示以
i
,
j
i,j
i,j为右下角的矩形的最大值,
a
[
i
]
[
j
]
a[i][j]
a[i][j]为向左的前缀和,
b
[
i
]
[
j
]
b[i][j]
b[i][j]为向上的前缀和,则
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
j
]
+
a
[
i
]
[
j
]
,
f
[
i
]
[
j
−
1
]
+
b
[
i
]
[
j
]
)
f[i][j]=max(f[i-1][j]+a[i][j],f[i][j-1]+b[i][j])
f[i][j]=max(f[i−1][j]+a[i][j],f[i][j−1]+b[i][j])。
#include<bits/stdc++.h>
using namespace std;
int n,m,a[555][555],b[555][555],f[555][555];
int main()
{
while(1){
memset(f,0,sizeof(f));
scanf("%d%d",&n,&m);
if(n==0&&m==0) break;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
a[i][j]=a[i][j-1]+a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&b[i][j]);
b[i][j]=b[i-1][j]+b[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i-1][j]+a[i][j],f[i][j-1]+b[i][j]);
}
}
printf("%d\n",f[n][m]);
}
}
https://www.luogu.com.cn/problem/P3847
题解:区间
d
p
dp
dp,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示区间
[
i
,
j
]
[i,j]
[i,j]为合法的最小操作数。若
a
[
i
]
=
=
a
[
j
]
a[i]==a[j]
a[i]==a[j],则
f
[
i
]
[
j
]
f[i][j]
f[i][j]与
f
[
i
+
1
]
[
j
−
1
]
f[i+1][j-1]
f[i+1][j−1]一样;否则
f
[
l
]
[
r
]
=
m
i
n
(
f
[
l
+
1
]
[
r
]
,
m
i
n
(
f
[
l
]
[
r
−
1
]
,
f
[
l
+
1
]
[
r
−
1
]
)
)
+
1
f[l][r]=min(f[l+1][r],min(f[l][r-1],f[l+1][r-1]))+1
f[l][r]=min(f[l+1][r],min(f[l][r−1],f[l+1][r−1]))+1。
#include<bits/stdc++.h>
using namespace std;
const int N=3010;
int n,a[N],f[N][N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) f[i][i]=0;
for(int i=1;i<n;i++){
if(a[i]==a[i+1]) f[i][i+1]=0;
else f[i][i+1]=1;
}
for(int len=3;len<=n;len++){
for(int l=1,r=l+len-1;r<=n;l++,r++){
f[l][r]=min(f[l+1][r],min(f[l][r-1],f[l+1][r-1]))+1;
if(a[l]==a[r]) f[l][r]=min(f[l+1][r-1],f[l][r]);
}
}
printf("%d",f[1][n]);
}