Codeforces 1132F Clear the String(區間dp)

傳送門

題意:給一個長度不超過500的字符串,每次可以消掉字符串中連續相同的一個子串,消去之後剩下的兩個串自動連在一起,問最少消多少次使字符串清空。

題解:區間dp,一看應該使O(n^{3})的但是第一把居然寫出來個O(n^{2})的。過了樣例交上去果然WA了,原因是沒有考慮最優解是講原串分成若干子串的情況。所以轉移時需要引入斷點k,從而複雜度多一個n。

比如

6

adabcb

就可以卡掉這個會WA的算法(正解在後面)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=504;
int n;
char s[N];
int f[N][N];

inline int read() {
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f; 
}
inline void smin(int &x,int y) {
	x=x>y?y:x;
}
int main() {
//	freopen("in.txt","r",stdin);
	n=read();
	scanf("%s",s+1);
	memset(f,INF,sizeof(f));
	for (register int i=1;i<=n;++i) f[i][i]=1;
	for (int len=2;len<=n;++len)
		for (int i=1;i+len-1<=n;++i) {
			int j=i+len-1;
			f[i][j]=min(f[i+1][j]+1,f[i][j-1]+1);
			if (s[i]==s[j]||s[i]==s[i+1])
				smin(f[i][j],f[i+1][j]);
			if (s[i]==s[j]||s[j]==s[j-1])
				smin(f[i][j],f[i][j-1]);
		}
/*	for (int i=1;i<=n;++i) {
		for (int j=1;j<=n;++j)
			printf("%-2d ",f[i][j]==INF?-1:f[i][j]);
		puts("");
	}*/
	printf("%d\n",f[1][n]);
	return 0;
}

正解

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=504;
int n;
char s[N];
int f[N][N];

inline int read() {
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*f; 
}
inline void smin(int &x,int y) {
	x=x>y?y:x;
}
int main() {
//	freopen("in.txt","r",stdin);
	n=read();
	scanf("%s",s+1);
	memset(f,INF,sizeof(f));
	for (register int i=1;i<=n;++i) f[i][i]=1;
	for (int len=2;len<=n;++len)
		for (int i=1;i+len-1<=n;++i) {
			int j=i+len-1;
			for (int k=i;k<j;++k)
				if (s[i]==s[j]) smin(f[i][j],f[i][k]+f[k+1][j]-1);
				else smin(f[i][j],f[i][k]+f[k+1][j]);
		}
	printf("%d\n",f[1][n]);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章