P4170 木板涂色(区间DP)
题目描述:
解题思路:
此题可以考虑使用区间 d p dp dp 求解。
a
i
a_i
ai 表示为目标状态中第
i
i
i 个位置的颜色。
设
f
i
,
j
f_{i,j}
fi,j 表示在一个
(
i
,
j
)
(i,j)
(i,j) 的区间内,使这个区间达到目标颜色需要的最少涂色次数。
可以考虑分类讨论两种情况:
-
若 a i = a j a_i=a_j ai=aj ,也就是说为 i i i 上色时可以同时为 j j j 上色,因此 j j j 可以被省略,也就是说这个状态等同于 f i , j − 1 f_{i,j-1} fi,j−1;也可以看做为 j j j 上色时顺便将 i i i 上色,因此 i i i 也能被省略,即为 f i + 1 , j f_{i+1,j} fi+1,j。
-
若 a i ≠ a j a_i\ne a_j ai=aj ,也就是说 i i i 和 j j j 不能同时上色,也就是说 i i i 和 j j j 其实可以看做是两个子区间的部分,而区间 ( i , j ) (i,j) (i,j) 则是由这连个子区间加起来得来的。因此我们用到区间 d p dp dp 的基本思想,枚举这两个子区间的断点(分割点) k k k ,使得 f i , k − 1 + f k , j f_{i,k-1}+f_{k,j} fi,k−1+fk,j 最小。
推出状态转移方程:
f
i
,
j
=
{
min
(
f
i
+
1
,
j
,
f
i
,
j
−
1
)
a
i
=
a
j
min
(
f
i
,
k
−
1
+
f
k
,
j
)
a
i
≠
a
j
,
k
=
i
+
1
⋯
j
f_{i,j}=\begin{cases} \min (f_{i+1,j},f_{i,j-1})&a_i=a_j\\ \\ \min(f_{i,k-1}+f_{k,j})&a_i\ne a_j,k=i+1\cdots j \end{cases}
fi,j=⎩⎪⎨⎪⎧min(fi+1,j,fi,j−1)min(fi,k−1+fk,j)ai=ajai=aj,k=i+1⋯j
考虑初始状态:若要涂的区间长度为
1
1
1 ,很显然涂的次数最少即为
1
1
1。
f
i
,
j
=
{
1
i
=
j
∞
i
≠
j
f_{i,j}=\begin{cases} 1&i=j\\ \\ \infty&i\ne j \end{cases}
fi,j=⎩⎪⎨⎪⎧1∞i=ji=j
CODE:
#include <iostream>
#include <cstring>
using namespace std;
string a;
int f[60][60];
int main()
{
cin>>a;
a=" "+a;
for(int i=0;i<=a.size();i++)
for(int j=0;j<=a.size();j++)
f[i][j]=0x3f3f3f3f;
f[0][0]=0;
for(int i=1;i<=a.size();i++)
f[i][i]=1;
int n=a.size();
for(int len=2;len<=n;len++)
{
for(int l=1;l+len-1<=n;l++)
{
int r=l+len-1;
if(a[l]==a[r])
{
f[l][r]=min(f[l+1][r],f[l][r-1]);
continue;
}
for(int k=l+1;k<=r;k++)
{
f[l][r]=min(f[l][k-1]+f[k][r],f[l][r]);
}
}
}
cout<<f[1][n-1]; //减1是因为n为a的长度,但并非最右端点。
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!