题意:
给你一个长度为n的字符串s,并且告诉你有m对字母不能相邻,问你最少在s中取出多少个字符能够使这个字符串合法。
题解:
表示状态:
dp[i] = max num of letters
考虑到第i个字符并且留下了该字符,i以及i之前留下的字符形成的字符串合法,留下字符的最多个数。
找出答案:
n - (max dp[i]) (0<=i<n)
如何转移:
开一个辅助数组pre[c],c为一个小写字母的序号('a'为0),意为当前以c结尾的最长字符串长度。
pre数组随着i的枚举而被不断更新,所以当前的pre数组中存的都是i以及i之前的答案。
假设现在考虑到第i个字符,要更新dp[i]的值。
if(s[i]-'a'和j可以相邻) dp[i] = max(dp[i], pre[j]);
枚举i,j即可。 (i<=0<n, 0<=j<26)
边界条件:
dp[1] = 1,把其他字符都去掉,只留第i个字符,dp最少为1。
并且刚开始所有的pre[c]为0。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 100005 5 #define MAX_A 30 6 #define INF 10000000 7 8 using namespace std; 9 10 int n,m; 11 int ans=0; 12 int dp[MAX_N]; 13 int pre[MAX_A]; 14 bool near[MAX_A][MAX_A]; 15 string s; 16 17 void read() 18 { 19 memset(near,false,sizeof(near)); 20 cin>>n>>s>>m; 21 for(int i=0;i<m;i++) 22 { 23 char a,b; 24 cin>>a>>b; 25 near[a-'a'][b-'a']=true; 26 near[b-'a'][a-'a']=true; 27 } 28 } 29 30 void solve() 31 { 32 memset(pre,0,sizeof(pre)); 33 for(int i=0;i<n;i++) 34 { 35 dp[i]=1; 36 for(int j=0;j<26;j++) 37 { 38 if(!near[s[i]-'a'][j]) 39 { 40 dp[i]=max(dp[i],pre[j]+1); 41 } 42 } 43 pre[s[i]-'a']=max(pre[s[i]-'a'],dp[i]); 44 ans=max(ans,dp[i]); 45 } 46 } 47 48 void print() 49 { 50 cout<<n-ans<<endl; 51 } 52 53 int main() 54 { 55 freopen("note.in","r",stdin); 56 freopen("note.out","w",stdout); 57 read(); 58 solve(); 59 print(); 60 }