【LG P4170】塗色
阿新 • • 發佈:2021-07-19
解析
題意是求對字串的最少染色次數,設 f[i][j]
為字串的子串 s[i]
~ s[j]
的最少染色次數,我們分析一下:
當 i==j
時,子串明顯只需要塗色一次,於是 f[i][j]=1
。
當 i!=j
且 s[i]==s[j]
時,可以想到只需要在首次塗色時多塗一格即可,於是 f[i][j]=min(f[i][j-1],f[i+1][j])
。
當 i!=j
且 s[i]!=s[j]
時,我們需要考慮將子串斷成兩部分來塗色,於是需要列舉子串的斷點,設斷點為 k
,那麼 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j])
。
總結一下就是:
\[\begin{equation} f_{i,j}= \begin{cases} 1 & i=j\\ \min(f_{i,j-1},f_{i+1,j}) & i\not=j,s_i=s_j\\ \min(f_{i,j},f_{i,k}+f_{k+1,j}) & i\not=j,s_i\not=s_j \end{cases} \end{equation} \]由於 f[i][j]
f[1][n]
即為答案。
程式碼
#include<bits/stdc++.h> using namespace std; char c[55]; int f[55][55]; int main() { scanf("%s",c+1); int n=strlen(c+1); memset(f,0x7F,sizeof(f)); for(int i=1; i<=n; i++) { f[i][i]=1; } for(int i=2; i<=n; i++) { for(int l=1; l<=n; l++) { int r=l+i-1; if(r>n) { break; } if(c[l]==c[r]) { f[l][r]=min(f[l+1][r],f[l][r-1]); } else { for(int k=l; k<r; k++) { f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]); } } } } printf("%d",f[1][n]); return 0; }
參考資料
P4170 塗色 - Loner_Knowledge 的部落格 - 洛谷部落格
本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。
限於本人水平,如果文章有表述不當之處,還請不吝賜教。