[ABC261G] Replace

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.

Input

Input is given from Standard Input in the following format:
\(S\)
\(T\)
\(K\)
\(C_1\) \(A_1\)
\(C_2\) \(A_2\)
.
.
.
\(C_k\) \(A_k\)

Output

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

Sample Input 1

ab
cbca
3
a b
b ca
a efg

Sample Output 1

4

Starting with S=ab, Takahashi can make T=cbca in four operations as follows:

  • Replace the 1-st character a in ab with b (Operation of the 1-st kind). The string is now bb.
  • Replace the 2-nd character b in bb with ca (Operation of the 2-nd kind). The string is now bca.
  • Replace the 1-st character b in bca with ca (Operation of the 2-nd kind). The string is now caca.
  • Replace the 2-nd character a in caca with b (Operation of the 1-st kind). The string is now cbca.

Each operation incurs a cost of 1, for a total of 4, which is the minimum possible.

Sample Input 2

a
aaaaa
2
a aa
a aaa

Sample Output 2

2

Two operationsaaaaaaaaa incur a cost of 2, which is the minimum possible.

Sample Input 3

a
z
1
a abc

Sample Output 3

-1

No sequence of operations makes \(T\)=z from \(S\)=a.
妙到极致的区间 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;
}
posted @ 2022-09-04 15:57  灰鲭鲨  阅读(275)  评论(0编辑  收藏  举报