题目描述
给出一个长度为n的字符串,每次可以删除一个字母相同的子串,问最少需要删多少次。 数据规模:n <= 500
输入格式
第1行:1个整数,表示字符串的长度
第2行:n个字符的字符串
输出格式
第1行:1个整数,表示答案
样例
样例输入
5
abaca
样例输出
3
此题即为典型的区间DP题,根据题目可以设以 dp[l,r]是为 l 到 r区间删除完字符串的最小次数,可分两种情况讨论:
一般情况下,dp[l,r]由长度可以通过 dp[l+1,r]或 dp[l,r−1]增加一个字符得到,此时取两者之间的最小值。
枚举 k∈(l,r),用 k作为决策点,如果 c[l]=c[k]即可以通过 dp[l][k−1]+dp[k][r]直接得到, 注意此处不需要加一, 因为c[l]和 c[k]是相同字符,所以可以直接删除,而在计算c[l] 和 c[k]时,已经加一所以,不需要加一!
#include
#include
#include
using namespace std;
const int M=1005;
char s[M];
int f[M][M];
int main(){
int n;
scanf("%d",&n);
scanf("%s",&s[1]);
for(int i=1;i<=n;i++){
f[i][i]=1;
}
for(int len=1;len<=n;len++){
for(int l=1;l<=n-len;l++){
int r=len+l;
if(s[l]==s[r]){
f[l][r]=f[l+1][r-1]+1;
}
else{
f[l][r]=min(f[l+1][r],f[l][r-1])+1;
}
for(int k=l;k<r;k++){
f[l][r]=min(f[l][r],f[l][k]+f[k][r]-1);
}
}
}
printf("%d",f[1][n]);
}
题目描述
给定一个字符串 s ,找到 s 中最长的回文子串,输出其长度。
你可以假设 s 的最大长度为 3000。
输入格式
第1行:1个字符串
输出格式
第1行:1个整数
样例
样例输入
babad
样例输出
3
这一道题比上一道题要稍妙简单一些
这一道题主要思想还是 f[l][r] 表示在 l 到 r 这个元区间里最长回文串的长度。所以一共有三种情况:
①当首尾相等 (即 a[l]=a[r] 时),且在 l 到 r 是回文数时
f[l][r]=f[l+1][r-1]+2;
(在这里有一个技巧来判断是否为回文数即 r-l-1)
②当首尾相等 (即 a[l]=a[r] 时),但 l 到 r 不是回文数时:
f[l][r]=max(f[l+1][r],f[l][r-1]);
③当首尾不相等时:
f[l][r]=max(f[l+1][r],f[l][r-1]);
#include
#include
#include
using namespace std;
const int M=10005;
int a[M],f[M][M];
char s[M];
void g(int n){
for(int i=1;i<=n;i++){
s[i]=s[i-1];
}
return ;
}
int main(){
scanf("%s",&s[1]);
int n=strlen(s+1);
for(int i=1;i<=n;i++)
f[i][i]=1;
for(int len=2;len<=n;len++){
for(int l=1;l<=n-len+1;l++){
int r=l+len-1;
if(s[l]==s[r]&&f[l+1][r-1]==r-l-1){
f[l][r]=f[l+1][r-1]+2;
}
else{
f[l][r]=max(f[l+1][r],f[l][r-1]);
}
}
}
printf("%d",f[1][n]);
}
输入一个长度为N的数字串, 用K个乘号将它分为 (K+1) 个部分,使得得到的乘积最大
例如N = 3 , K = 1,输入的数字串为 312
分法有两种
3*12 = 36
31*2 = 62
最大值为62
输入格式
输入共两行
第一行,正整数 N 和 K
第二行,一个数字串
输出格式
用K个乘号将数字串划分为(K+1)个部分所得到的最大乘积
样例
####样例输入1
3 1
312
####样例输出1
62####样例输入2
7 3
3314245
####样例输出2
278040
这一题与前两道题不一样,不同点在于 f[i][j] 含义的改变,这里的 i 表示一共有 i 个乘号加入到式子里面来;而 j 表示 1~j 这一个区间。
这里有一个字符转换为数的方式
long long get(int i,int j){
long long ans=0;
for(int k=i;k<=j;k++){
ans=ans*10+a[k]-'0';
}
return ans;
}
接下来就是状态转移方程
f[i][j] = max{ f(i-1, k) * get(k+1, j) } (1<=i<=m, i+1<=j<=n, i<=k
#include
#include
#include
using namespace std;
const int M=10005;
long long f[M][M];
char a[M];
long long get(int i,int j){
long long ans=0;
for(int k=i;k<=j;k++){
ans=ans*10+a[k]-'0';
}
return ans;
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
scanf("%s",a+1);
for(int i=1;i<=n;i++){
f[0][i]=get(1,i);
}
for(int i=1;i<=m;i++){
for(int j=i+1;j<=n;j++){
for(int k=i;k<j;k++){
f[i][j]=max(f[i-1][k]*get(k+1,j),f[i][j]);
}
}
}
printf("%lld",f[m][n]);
}
写博客不易,点个赞再走!