您的位置:首页 > 其它

bzoj 2121 字符串游戏

2015-11-16 10:40 316 查看
BX正在进行一个字符串游戏,他手上有一个字符串L,以及其他一些字符串的集合S,然后他可以进行以下操作:对于一个在集合S中的字符串p,如果p在L中出现,BX就可以选择是否将其删除,如果删除,则将删除后L分裂成的左右两部分合并。举个例子,L='abcdefg' , S={'de'},如果BX选择将'de'从L中删去,则删后的L='abcfg'。现在BX可以进行任意多次操作(删的次数,顺序都随意),他想知道最后L串的最短长度是多少。
f[i][j][k][p]表示i到j是否可以表示第k个字符串的前p个字符。c[i][j]表示i到j是否可以全部删去。有两种转移‘f[j-1][k][p-1]&&st[k][p]==S[j]f[d][k][p]&&c[d+1][j]类似区间dp的东西可以采用固定一端,枚举另一端的方法
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>

#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
#define N
using namespace std;
bool f[170][35][25],c[170][170];
int dp[170],len[35];
char S[170],st[35][25];
int main()
{
	scanf("%s",S+1); int lth=strlen(S+1);
	int n;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",st[i]+1);
		len[i]=strlen(st[i]+1);
	}
	for (int i=lth;i;i--)
	{
		memset(f,0,sizeof(f));
		for (int k=1;k<=n;k++)
		  f[i-1][k][0]=1;
		for (int j=i;j<=lth;j++)
		{
			for (int k=1;k<=n;k++)
				for (int p=1;p<=len[k];p++)
					f[j][k][p]|=(f[j-1][k][p-1]&&st[k][p]==S[j]);
			for (int d=i;d<=j;d++)
			  if (c[d+1][j])
			  {
			  	for (int k=1;k<=n;k++)
			  	   for (int p=1;p<=len[k];p++)
			  	     f[j][k][p]|=f[d][k][p];
			  }
		}
		for (int j=i;j<=lth;j++)
		  for (int k=1;k<=n;k++)
		    c[i][j]|=f[j][k][len[k]];
	}
	for (int i=1;i<=lth;i++)
	{
	  dp[i]=dp[i-1]+1;	
	  for (int j=1;j<=i;j++)
	    if (c[j][i]) dp[i]=min(dp[i],dp[j-1]);
	}
	printf("%d\n",dp[lth]);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: