题目大意:给你一个字符串,要你按每组k个按照顺序进行分组,每组里的字母顺序可以乱动,然后再按照组的顺序拼起来,如果相邻的几个相同的字母算一个“chunks”,问你拼起来后,最少的“chunks”是多少?
思路:简单DP题,要最小每个组里相同字母肯定是放在一起的,然后如果拼接时上一个的尾,和这一个的头字母是一样的,那么就要两者和减一,设d[ i ][ j ] 表示前i,且第i个的尾部的字母是j的最小个数,那么d[ i ][ j ] = min(d[ i -1][ p ]-c),如果第i组首字母和p相同,那么c为1,否则c为0。判断首字母和上一组的尾字母是否相同时,要注意,不是第i组有就行,还要这个(p!=j || 第i组总字母种数就为1)。
因为自己做的时候上面那个判断写错了,WA了,去网上看,发现大家都是三维做的,于是乎,我又感觉好像是要三维,就按照三维的做了一遍,A了之后,自己仔细想想,这个题没必要三维啊,只标记尾部就可以了呀,然后又去检查了一遍自己第一遍时WA的代码,发现了这个错误,一交果然AC,时间、空间上都好了很多。
以下是最后发现错误,自己写的两维的代码:
#include<cstdio> #include<cstring> #include<set> #include<algorithm> using namespace std; const int INF = 0xfffffff ; const int MAXN = 1111 ; char str[MAXN]; int d[MAXN][256]; set <char> s; int len,unit,group; int vis[256]; void gao(int x) { memset(vis,0,sizeof(vis)); s.clear(); for(int i = x*unit;i<(x+1)*unit;i++) { vis[str[i]]=1; s.insert(str[i]); } } void init() { for(int i = 0;i<group;i++) for(int j = 'a' ;j<='z';j++) d[i][j] = INF; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&unit); scanf("%s",str); len = strlen(str); group = len/unit; init(); gao(0); set <char> :: iterator it ; for( it = s.begin();it!=s.end();it++) d[0][(*it)] = s.size(); for(int i = 1;i<group;i++) { gao(i); int tot = s.size(); //printf("i = %d,tot = %d\n",i,tot); for(it = s.begin();it!=s.end();it++) { int j = *it; for(int p = 'a';p<='z';p++) { int del; if(vis[p]&&(j!=p||tot==1)) del = 1; else del = 0; d[i][j] = min(d[i][j],tot+d[i-1][p]-del); } } } int ans = INF; for(int i = 'a';i<='z';i++) ans = min(ans,d[group-1][i]); printf("%d\n",ans); } return 0; }
这个是WA了之后,看网上,写的三维的代码:
#include<cstdio> #include<cstring> #include<set> #include<algorithm> using namespace std; const int INF = 0xfffffff ; const int MAXN = 1111 ; char str[MAXN]; int d[MAXN][26][26]; set <int> s; int len,unit,group; void gao(int x) { s.clear(); for(int i = x*unit;i<(x+1)*unit;i++) { s.insert(str[i]-'a'); } } void init() { for(int i = 0;i<group;i++) for(int j = 0 ;j<26;j++) for(int l = 0;l<26;l++) d[i][j][l] = INF; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&unit); scanf("%s",str); len = strlen(str); group = len/unit; init(); set <int> :: iterator it,it2; gao(0); for( it = s.begin();it!=s.end();it++) for( int i = 0;i<26;i++) d[0][i][(*it)] = s.size(); for(int i = 1;i<group;i++) { gao(i); int tot = s.size(); //printf("i = %d,tot = %d\n",i,tot); for(it = s.begin();it!=s.end();it++) for(it2 = s.begin();it2!=s.end();it2++) { int head = (*it),rear = (*it2); int add =0; if(head==rear) { if(tot==1) add=0; else add=1; } else add=0; for(int j = 0;j<26;j++) { for(int k = 0;k<26;k++) d[i][head][rear] = min(d[i-1][j][k]+tot+add-(head==k ? 1:0),d[i][head][rear]); } } } int ans = INF; for(int i = 0;i<26;i++) for(int j= 0;j<26;j++) ans = min(ans,d[group-1][i][j]); printf("%d\n",ans); } return 0; }