1. 程式人生 > 其它 >The Cow Lexicon S

The Cow Lexicon S

題目描述

Few know that the cows have their own dictionary with W (1 ≤ W ≤ 600) words, each containing no more 25 of the characters 'a'..'z'. Their cowmunication system, based on mooing, is not very accurate; sometimes they hear words that do not make any sense. For instance, Bessie once received a message that said "browndcodw". As it turns out, the intended message was "browncow" and the two letter "d"s were noise from other parts of the barnyard.

The cows want you to help them decipher a received message (also containing only characters in the range 'a'..'z') of length L (2 ≤ L ≤ 300) characters that is a bit garbled. In particular, they know that the message has some extra letters, and they want you to determine the smallest number of letters that must be removed to make the message a sequence of words from the dictionary.

輸入格式

Line 1: Two space-separated integers, respectively: W and L

Line 2: L characters (followed by a newline, of course): the received message

Lines 3..W+2: The cows' dictionary, one word per line

輸出格式

Line 1: a single integer that is the smallest number of characters that need to be removed to make the message a sequence of dictionary words.

樣例 #1

樣例輸入 #1

6 10
browndcodw
cow
milk
white
black
brown
farmer

樣例輸出 #1

2

提示

感謝@ws_fuweidong 提供完整題面
首先考慮暴力。設計\(dp_i\)表示前i個字元要去掉多少個字元可以被翻譯。暴力轉移就是列舉上一位在j,在j+1i中只能有一個單詞,那麼列舉是找到j+1i中最長的那個單詞。

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int w,l,dp[N],len[N];
char s[N][N],t[N];
int can(int x,int y)
{
	int ans=y-x+1;
	for(int k=1;k<=w;k++)//列舉選哪一種單詞
	{
		int r=1;
		for(int i=x;i<=y;i++)
		{
			if(s[k][r]==t[i])
				++r;
			if(r>len[k])//可以匹配上
				ans=min(ans,y-x+1-len[k]);
		}
	}
	return ans;
}
int main()
{
	scanf("%d%d%s",&w,&l,t+1);
	for(int i=0;i<=l;i++)
		dp[i]=i;
	for(int i=1;i<=w;i++)
		scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);
	for(int i=1;i<=l;i++)
		for(int j=0;j<i;j++)
			dp[i]=min(dp[i],dp[j]+can(j+1,i));
	printf("%d",dp[l]);
	return 0;
}

但是會超時獲得70分。我們發現可以預處理出每個can(l,r)。列舉l和選哪種單詞,然後往後推r,如果一個單詞在某一處可以被匹配那麼在後面都可以匹配的上。

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int w,l,dp[N],len[N],f[N][N];
char s[N][N],t[N];
int can(int x,int y)
{
	int ans=2e9;
	for(int k=1;k<=w;k++)
	{
		int r=1;
		for(int i=x;i<=y;i++)
		{
			if(s[k][r]==t[i])
				++r;
			if(r>len[k])
				ans=min(ans,y-x+1-len[k]);
		}
	}
	return ans;
}
int main()
{
	memset(f,0x7f,sizeof(f));
	scanf("%d%d%s",&w,&l,t+1);
	for(int i=0;i<=l;i++)
		dp[i]=i;
	for(int i=1;i<=w;i++)
		scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);
//	return can(6,10);
	for(int i=1;i<=l;i++)
	{
		int ans=2e9;
		for(int k=1;k<=w;k++)
		{
			int r=1;
			for(int j=i;j<=l;j++)
			{
				if(s[k][r]==t[j])
					++r;
				if(r>len[k])
					f[i][j]=min(f[i][j],j-i+1-len[k]);
			}
		}
	}
	for(int i=1;i<=l;i++)
		for(int j=0;j<i;j++)
			dp[i]=min(dp[i],dp[j]+f[j+1][i]);
	printf("%d",dp[l]);
	return 0;
}