首页 > 其他分享 >Replace

Replace

时间:2022-09-04 16:13:40浏览次数:45  
标签:string int Replace 变为 k1 代价 dp

Problem Statement

You are given two strings \(S\) and \(T\) consisting of lowercase English letters.

Takahashi starts with the string \(S\). He can perform K kinds of operations any number of times in any order.
The i-th operation is the following:

Pay a cost of \(1\). Then, if the current string contains the character \(C_i\), choose one of its occurrences and replace it with the string \(A_i\) . Otherwise, do nothing.

Find the minimum total cost needed to make the string equal \(T\). If it is impossible to do so, print −1.

Constraints

  • \(1≤∣S∣≤∣T∣≤50\)
  • \(1≤K≤50\)
  • \(C\) is a,b...z
  • \(1\le |A_i|\le 50\)
  • \(S\), \(T\), and \(A_i\)are strings consisting of lowercase English letters.
  • \(C_i\ne A_i\), regarding \(C_i\) as a string of length 1.
  • All pairs \((C_i,A_i)\) are distinct.

妙到极致的区间 dp。

发现字符变为字符串不好做,所以我们反过来,字符串变为字符。同时发现变换方式有区间的痕迹,考虑区间 dp。

区间 dp 使用需要让区间变小。所以当 \(|A_i|=1\) 时,要特判。可以跑 Floyd。注意不要打错(打错 Floyd 调了好久

定义 \(dp_{l,r,c}\) 为 \(t[l,r]\) 变换成字符 \(c\) 的最小代价。这个区间 dp 难在转移。枚举使用哪一种变换方式。设使用第 \(i\) 种变换,那么 \(t[l,r]\) 变为 \(c_i\) 的代价为 \(t[l,r]\) 变为 \(A_i\) 的代价加 1。算完后我们把 Floyd 的结果跑一遍。算答案时我们也是计算 \(t[1,n]\) 变为 s 的代价。

所以我们唯一不会算的就是 \(t\) 的一个子串串变为另一个字符串的代价。设这个子串为 \(t[l,r]\),

考虑做另一个 dp 方程。设 \(g_{i,j}\) 为把 \(t_l\) 至 \(t_j\) 变为\(A_{i,1}\) 至 \(A_{i,k}\) 最小代价。转移时枚举最后一次变换的开头 \(k1\),那么\(g_{j,k}=\min \limits_{k1=l-1}^rg_{k1,k-1}+dp_{k1+1,j,A_{i,k}}\)

代码还挺绕的,建议写注释。同时要一步步理解。

#include<bits/stdc++.h>
using namespace std;
const int N=55;
char s[N],t[N],c[N],str[N][N];
int dis[27][27],dp[N][N][27],p,g[N][N],d[N],n,m,r;
int main()
{
	memset(dis,0x3f,sizeof(dis));
	memset(dp,0x3f,sizeof(dp));
	scanf("%s%s%d",s+1,t+1,&p);
	n=strlen(t+1),m=strlen(s+1);
	for(int i=1;i<=p;i++)
	{
		scanf(" %c%s",&c[i],str[i]+1);
		d[i]=strlen(str[i]+1);
		if(d[i]==1)
			dis[str[i][1]-'a'][c[i]-'a']=1;
//		printf("%d\n",d[i]);
	}
	for(int i=1;i<=n;i++)
		dp[i][i][t[i]-'a']=0;
	for(int k=0;k<27;k++)
		for(int i=0;i<27;i++)
			for(int j=0;j<27;j++)
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
	for(int len=1;len<=n;len++)
	{
		for(int l=1;l+len-1<=n;l++)//从t[l]至t[r]变到c的最小代价 
		{
			r=l+len-1;
			for(int i=1;i<=p;i++)//考虑第i次操作 
			{
				if(d[i]>len)
					continue;
				memset(g,0x3f,sizeof(g));
				g[l-1][0]=0;
				for(int k=1;k<=d[i];k++)
				{
					for(int j=l-1;j<=r;j++)//把t[l]至t[j]变为str[i][1]至str[i][k]最小代价 
					{
						for(int k1=l-1;k1<j;k1++)//已经把t[l]...t[k1]变成str[i][1]...str[i][k-1]
							g[j][k]=min(g[j][k],g[k1][k-1]+dp[k1+1][j][str[i][k]-'a']);
					}
				}
//				if(l==3&&r==4)
//					printf("%d\n",g[3][1]);
				dp[l][r][c[i]-'a']=min(dp[l][r][c[i]-'a'],g[r][d[i]]+1);
			}
			for(int i=0;i<27;i++)
				for(int j=0;j<27;j++)
					dp[l][r][i]=min(dp[l][r][i],dp[l][r][j]+dis[j][i]);
		}
	}
//	printf("%d\n",dp[2][2][0]);
//	printf("%d\n",dp[2][2][1]+dis[1][0]);
	memset(g,0x3f,sizeof(g));
	g[0][0]=0;
	for(int k=1;k<=m;k++)
	{
		for(int j=0;j<=n;j++)//把t[l]至t[j]变为str[i][1]至str[i][k]最小代价 
		{
			for(int k1=0;k1<j;k1++)//已经把t[l]...t[k1]变成str[i][1]...str[i][k-1]
				g[j][k]=min(g[j][k],g[k1][k-1]+dp[k1+1][j][s[k]-'a']);
		}
	}
	if(g[n][m]>1e9)
		printf("-1\n");
	else
		printf("%d",g[n][m]);
	return 0;
}

标签:string,int,Replace,变为,k1,代价,dp
From: https://www.cnblogs.com/mekoszc/p/16655280.html

相关文章