原题
题目拷贝自 libin_vincent的博客 和 半山居士的博客
给定两个长度为 n ( 0 < n <= 8 ) 的 数字串 (由1到9构成) ,我们希望对第一个数字串做一系列如下操作:
1、将数字串的某一位加1
2、将数字串的某一位减1
3、交换数字串中任意两个数字的位置
最终使得第一个数字串变成第二个数字串, 请问最少需要多少操作。
解析
采用动态划划的办法,对于两个数字串a和b, 假设最小的交换次数为S,解之间满足如下关系
S(a,b) = min_(0<=j<=n) [ j==0 + abs(a[j]-b[0]) + S(a.swap(0,j)[1:n],b[1:n]) ]
第一项 j==0 代表对a[0]和a[j]进行交换之后,操作次数+1 (不交换的话次数为0)
第二项 abs(a[j]-b[0]) 代表将a[j] 变换为b[0]的加减操作次数
第三项 代表 将a[0]和a[j]进行交换之后,a[1:n] 和b[1:n]之间的最小交换次数
代码
#include <iostream>
#include <cmath>
#include <vector>
#include <string>
using namespace std;
void swap_vect(vector<int> &a, int i, int j){
int temp = a[j];
a[j] = a[i];
a[i] = temp;
};
vector<int> one_to_end_Vector(vector<int> a){
vector<int> result(a.size()-1);
for (int i=1;i<a.size();++i){
result[i-1] = a[i];
}
return result;
};
int numStrSwapVect(vector<int> a,vector<int> b){
if (a.size()==1) return abs(a[0] - b[0]);
int min_ops = 999999;
int n = a.size();
for (int i=0;i<n;++i){
swap_vect(a,0,i);
int temp = (i!=0) +abs(a[0] - b[0])+
numStrSwapVect(one_to_end_Vector(a),one_to_end_Vector(b));
if (temp<min_ops) min_ops=temp;
swap_vect(a,0,i);
};
return min_ops;
};
int numStrSwap(string src, string dst) {
int n = src.size();
vector<int> a(n);
vector<int> b(n);
for (int i=0;i<n;++i){
a[i] = (int) src[i];
b[i] = (int) dst[i];
}
// calculate the distance
return numStrSwapVect(a,b);
}
int main() {
string a,b;
cout<<"Input two integer strings in two rows"<< endl;
cin>>a;
cin>>b;
if (a.size()!=b.size()){
cout<<"Error: unequal length"<< endl;
return 0;
}
int result = numStrSwap(a,b);
cout<<"Minimum operations are "<< result<<endl;
return 0;
}
编译及执行结果为
g++ -O3 a.cpp -o a.out
./a.out
Input two integer strings in two rows
1234
5421
Minimum operations are 4
Input two integer strings in two rows
24
45
Minimum operations are 3
Input two integer strings in two rows
1234
2341
Minimum operations are 3