天天看點

ACM 94. [NOIP2001] 統計單詞個數(劃分dp) 94. [NOIP2001] 統計單詞個數

94. [NOIP2001] 統計單詞個數

★☆   輸入檔案:

tjdcgs.in

   輸出檔案:

tjdcgs.out

    簡單對比

時間限制:1 s   記憶體限制:128 MB

Description

給出一個長度不超過200的由小寫英文字母組成的字母串(約定;該字串以每行20個字母的方式輸入,且保證每行一定為20個)。要求将此字母串分成k份(1<k≤40),且每份中包含的單詞個數加起來總數最大(每份中包含的單詞可以部分重疊。當選用一個單詞之後,其第一個字母不能再用。例如字元串this中可包含this和is,選用this之後就不能包含th)。 單詞在給出的一個不超過6個單詞的字典中。要求輸出最大的個數。

Input

(在正式輸入前有一行一個1,代表資料組數)

第一行有2個正整數p,k。p表示字串的行數;k表示分為k個部分。

接下來的p行,每行均有20個字元。

再接下來有一個正整數s,表示字典中單詞個數。(1≤s≤6)

接下來的s行,每行均有一個單詞。

Output

僅一行,一個整數,表示劃分出來的最多單詞個數。

Sample Input

1

1 3

thisisabookyouareaoh

4

is

a

ok

sab

Sample Output

7

Hint

按如下方式劃分字元串:

this/isabookyoua/reaoh

優化:預先把字典中的詞語長度求出來

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define INF 9999999

int T;
int p,k;
char readstr[1000];
char text[1000];
char dic[20][1000];
int dcnt;
int d[1000][21];
int len[20];

bool cmp(const char *a,const char *b)
{
	while(*b)
	{
		if(!*a) return false;
		if(*a!=*b) return false;
		a++;b++;
	}

	return true;
}

int GetCount(int s,int t)
{
	int cnt=0;

	for(int i=s;i<=t;i++)
	{
		for(int j=0;j<dcnt;j++) if(t-i+1>=len[j] && cmp(&text[i],dic[j]))
		{
			cnt++;
			break;
		}
	}
	return cnt;
}

int dp(int t,int k)
{
	int minx=0;
	if(t<k) return -INF;
	if(k==0)
	{
		return GetCount(0,t);
	}
	if(d[t][k]>=0) return d[t][k];

	for(int i=0;i<t;i++)
	{
		minx=max(minx,dp(i,k-1)+GetCount(i+1,t));
	}

	return d[t][k]=minx;
}

int main()
{
	freopen("tjdcgs.in","r",stdin);
	freopen("tjdcgs.out","w",stdout);

	scanf("%d",&T);

	while(T--)
	{
		scanf("%d%d",&p,&k);
		for(int i=0;i<p;i++)
		{
			scanf("%s",readstr);
			strcat(text,readstr);
		}
		scanf("%d",&dcnt);
		for(int i=0;i<dcnt;i++)
		{
			scanf("%s",dic[i]);
			len[i]=strlen(dic[i]);
		}
		memset(d,-1,sizeof(d));
		cout<<dp(strlen(text)-1,k-1)<<endl;
	}

	return 0;
}
           
dp