【codechef】Magical Transformation(dp,技巧题)

Irfan and his brother Yusuf were looking at photographs of their vacation to Hawaii. Irfan noticed something interesting. He noticed that if their aunt Mansi had a big beard and a moustache she would resemble their uncle Amit. He tried to modify the people in other photographs in such a way so that they would resemble someone else. Yusuf who was into programming decided to do something similar with strings. He wrote down 2 words and tried to transform one word into another.

He decided that the operations that maybe performed on the strings could be: Inserting a character at any position, removing an existing character, modifying an existing character and swapping 2 adjacent characters. Each operation is counted as one move. While doing this he noticed that there is more than one way to complete this transformation. He wants your help to write a program that can find out the minimum number of moves required transform a given word into another given word.

Input

  • The first line contains a single integer T , the number of test cases. T test cases follow.
  • The only line of each test case contains 2 strings (contains only lower case letters), separated by a single space.

Output

For each test case, output a single line containing an integer which denotes the minimum number of moves required transform a given word into another given word.

Constraints

  • 1 ≤ T ≤ 1000
  • 1 ≤ |S| ≤ 100

 

Example

Input:
1
smatr smart

Output:
1

http://www.codechef.com/problems/MOUSCH01

有四种操作: Inserting a character at any position, removing an existing character, modifying an existing character and swapping 2 adjacent characters

问把一个字符串转变成另一个字符串所需要的最少操作数。

dp[i][j]表示取到A的前i位B的前j位时所需要的最少操作数。下面解释一下核心代码:

dp[i][j]=min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1首先考虑的是前三种操作。dp[i-1][j-1]是修改j位置上的值,dp[i-1][j]侧重在i<j的情况下删除j的末尾,dp[i][j-1]侧重在i>j的情况下在j的末尾插入值。接下来的代码考虑的是swap。由于是相邻,last数组记录字母在字符串中最后一次出现的位置,观察是否有其中一方要交换的两个字母刚好在相邻位置。如12345和15234,当前的两个末尾是4和5,分别在另一个字符串里查找4和5最后一次出现的位置,5->2,5->4,由于在A中4和5出现的位置相邻,那么我们可以选择交换4和5(+1),再加上dp[3][1]的状态,在此基础上往5后面插入2和3即可。

#include<iostream>  
#include<algorithm>  
#include<string>  
#include<map>  
#include<vector>  
#include<cmath>  
#include<string.h>  
#include<stdlib.h>  
#include<cstdio>  
#define ll long long  
using namespace std;  
int dp[101][101];
int last1[28],last2[28];
int main(){
	int t;
	cin>>t;
	while(t--){
		char x[105],y[105];
		cin>>x>>y;
		int len1=strlen(x),len2=strlen(y);
		for(int i=len1;i>=1;--i)
			x[i]=x[i-1];
		for(int i=len2;i>=1;--i)
			y[i]=y[i-1];
		for(int i=0;i<=len1;++i)
			dp[i][0]=i;
		for(int i=1;i<=len2;++i)
			dp[0][i]=i;
		memset(last1,-1,sizeof(last1));
		for(int i=1;i<=len1;++i){
			memset(last2,-1,sizeof(last2));
			for(int j=1;j<=len2;++j){
				if(x[i]==y[j])
					dp[i][j]=dp[i-1][j-1];
				else{
					dp[i][j]=min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
					if(last1[y[j]-'a']>0&&last2[x[i]-'a']>0){
						if(last1[y[j]-'a']==i-1)  //可以这样做的原因是[swapping 2 adjacent characters]
							dp[i][j]=min(dp[i][j],dp[last1[y[j]-'a']-1][last2[x[i]-'a']-1]+j-last2[x[i]-'a']-1+1);
						else if(last2[x[i]-'a']==j-1)
							dp[i][j]=min(dp[i][j],dp[last1[y[j]-'a']-1][last2[x[i]-'a']-1]+i-last1[y[j]-'a']-1+1);
					}
				}
				last2[y[j]-'a']=j;
			}
			last1[x[i]-'a']=i;
		}
		cout<<dp[len1][len2]<<endl;
	}
	return 0;
}


你可能感兴趣的:(【codechef】Magical Transformation(dp,技巧题))