网易雷火笔试-打印机(区间dp)



有一台神奇的打印机,可打印的字母范围大写A-Z,每次只能从纸带上的任意位置开始打印同一字母任意次数,并且可以覆盖之前同一位置上已经打印上的字母。给定一个目标字符串,问最少需要打印多少次才能打印出给定字符串。例如,目标为ABCBA,先打印AAAAA,再打印BBB,再打印C,所以答案为3。

分析:没什么难的,看到有划水过去的,但是答案是错的,有求联通块的,不理解是怎么建的图

我是用的区间dp,dp[i][j]表示打印【i,j】需要的打印数,[l,r]最差的选择是在[l,j-1]的基础上在末尾单独的添加上那一个字符,所以dp[i][j]最大为dp[i][j-1]+1

那么dp[i][j]=min(dp[i][t]+d[t+1][j-1]),但是要注意会产生非法访问(即i>j)dp的只有在类似"AA"这样的子串的时候才会发生,将dp非法访问的都置为1就好了,或者这样情况手动处理

有的人思路认为如果找到一个t<j使得s[t]==s[j],那么dp[i][j]=dp[i][t]+{(t+1)-(j-1)之间的不同字符数},但是ADBDBA这样的样例是过不去的

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e3+5;
 4 int dp[maxn][maxn];
 5 char s[maxn];
 6 
 7 int solve(){
 8     int n=strlen(s);
 9     memset(dp,0,sizeof(dp));
10     for(int i=0;i<n;i++)dp[i][i]=1;
11     
12     for(int k=2;k<=n;k++){
13         for(int i=0;i<=n-k;i++){
14             int j=i+k-1;
15             dp[i][j]=dp[i][j-1]+1;
16             for(int t=j-1;t>=i;t--)
17                 if(s[t]==s[j])
18                     dp[i][j]=min(dp[i][t]+dp[t+1][j-1],dp[i][j]);
19             //cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
20         }
21         
22     }
23     return dp[0][n-1];
24 }
25 
26 int main(){
27     cin>>s;
28     cout<<solve()<<endl;
29 
30     return 0;
31 }
View Code

 

posted @ 2017-03-21 11:02  N维解析几何  阅读(601)  评论(0编辑  收藏  举报