poj3267

13 篇文章 0 订阅
涉及算法:dp
题目大意:现有一个长度为m的字符串s和n个单词,现在需要删除字符串中的某些字符,使得剩下的部分可以用n个单词的中的某些来表示,求最少需要删除多少个字符。
题目分析:设dp[i]表示从s的第0个字符开始长度为i的字符串(末位位i-1,后面的字符不考虑)需要删除的字符数,则dp[i]是取决于dp[1]~dp[i-1]的,如果s[i]加上其前面的一些字符(可以不连续)能和某个word匹配,则dp[i]取决于dp[k]和匹配需要该word需要从s中删除的字符数,k为s与该word匹配的最后一个字符的索引,若s[i]加上其前面的一些字符(可以不连续)不能某个word匹配,则s[i]显然是要删除,那么dp[i]=dp[i-1]+1;根据这些分析,可以得到如下的状态转移方程:

其中k为和该word匹配的最后一个字符的索引。

代码如下:
package com.solo.dp;

import java.util.Scanner;

public class Main_3267 {
	
	static String[] word;//用来匹配字符串的单词
	static char[] str;//字符串
	static int[] len;//len[i]:第i个单词的长度
	static int[] dp;//dp[i]:
	static int m;//字符串长度
	static int n;//单词个数
	
	public static void main(String[] args) 
	{
		Scanner in=new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		dp=new int[m+1];
		word=new String[n];
		len=new int[n];
		String s=in.next();
		str=s.toCharArray();
		for(int i=0;i<n;i++)
		{
			word[i]=in.next();
			len[i]=word[i].length();
		}
		
		dp();
		System.out.println(dp[0]);
	}

	//从后往前走
	static void dp(){
		//dp[i]:表示从第i位到末位需要删除的字符个数
		dp[m]=0;
		for(int i=m-1;i>=0;i--)
		{	
			dp[i]=dp[i+1]+1;
			for(int j=0;j<n;j++)
			{
				if((m-i)>=len[j] && str[i]==word[j].charAt(0))//若str[i]和word的第一个字符不一样,则str[i]肯定是要删除的
				{
					int wid=1;
					for(int k=i+1;k<m;k++)
					{
						if(str[k]==word[j].charAt(wid))
						{
							wid++;	
							if(wid==len[j])
							{//匹配成功
								dp[i]=Math.min(dp[i],dp[k+1]+k-i+1-len[j]);
								break;
							}
						}
					}
				}
			}
		}
	}
	//从前往后走
	static void dp2(){
		//dp[i]:表示从第0位开始长度为i的字符串(末位为第i-1个字符)
		dp[0]=0;
		for(int i=1;i<=m;i++)
		{	
			dp[i]=dp[i-1]+1;
			for(int j=0;j<n;j++)
			{
				if(str[i-1]==word[j].charAt(len[j]-1) && i>=len[j])
				{
					int wid=len[j]-2;
					for(int k=i-2;k>=0;k--)
					{
						if(str[k]==word[j].charAt(wid))
						{
							wid--;
							if(wid==-1)
							{
								dp[i]=Math.min(dp[i], dp[k]+i-k-len[j]);
								break;
							}
						}
					}
				}
			}
		}	
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值