题目链接:https://www.luogu.com.cn/problem/P7414
分析
区间DP经典题,设 f [ i ] [ j ] f[i][j] f[i][j]为涂完 i − j i-j i−j所需要的最小涂色次数。
先考虑边界: f [ i ] [ i ] = 1 , f [ i ] [ j ] = i n f ( i ! = j ) f[i][i]=1,f[i][j]=inf(i!=j) f[i][i]=1,f[i][j]=inf(i!=j)
然后枚举区间长度和起点,算出终点,如果两端是相等的,颜色可以延伸过去一次涂完,不需要两次,这里就是
f
[
i
]
[
j
]
=
m
i
n
(
f
[
i
+
1
]
[
j
]
,
f
[
i
]
[
j
−
1
]
)
f[i][j]=min(f[i+1][j],f[i][j-1])
f[i][j]=min(f[i+1][j],f[i][j−1])
如果两端不同,就枚举一个中间点k,把
f
f
f数组中总和最小的两端加起来,从部分到整体,推出
f
[
i
]
[
j
]
f[i][j]
f[i][j]。方程:
f
[
i
]
[
j
]
=
m
i
n
(
f
[
i
]
[
j
]
,
f
[
i
]
[
k
]
+
f
[
k
+
1
]
[
j
]
)
(
i
<
=
k
<
=
j
−
1
)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])(i<=k<=j-1)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])(i<=k<=j−1)
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[305],f[1001][1001];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
f[i][i]=1;
for(int j=1;j<=n;j++)
{
if(i!=j) f[i][j]=20070819;
}
}
for(int len=1;len<=n;len++)
{
for(int i=1;i+len<=n;i++)
{
int j=i+len;
if(a[i]==a[j]) f[i][j]=min(f[i][j-1],f[i+1][j]);
else
{
for(int k=i;k<=j-1;k++)
{
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
}
cout<<f[1][n];
return 0;
}