动态时间规整是一种用于对齐向量,并计算最小距离的算法,个人感觉其思想和LCS十分类似。
同样,设两个向量为x,y,First(x)表示x的第一个元素,Rest(x)表示除第一个元素以外的x的剩余元素组成的向量
采用欧氏距离作为距离度量,即向量间的距离用对应元素的平方和再开根号表示,即:
D(A,B) = sqrt [ ∑( ( a[i] - b[i] )^2 ) ] (i = 1,2,…,n)
用D(x,y)表示x,y的DTW距离
定义:两个向量x,y的DTW距离为:
思路:设x长度为n,y长度为m,搜索过程就是在n*m的网格中寻找一条路径,使路径所经过的点对应的x[i],y[j]的距离的平方和最小。
每次搜索时,先计算当前网格中的x[i],y[j]的距离的平方,然后向网格x轴,y轴和对角线三个方向递归搜索,寻找距离最小的路径。
类似LCS,DTW也可以用动态规划方便的实现,搜索空间为n*m
设dp[i][j]表示以x[i]和y[j]开始的子序列的DTW距离,则递归方程为:
dp[i][j] = (x[i]-y[j])^2 + MIN(dtw(i+1,j+1),dtw(i+1,j),dtw(i,j+1))
注意递归边界,先将搜索终点dp[n-1][m-1]赋值。
例:给定x="ABAC",y="DADDAC"
匹配路径如下图所示:
每个网格的数字表示路径在该点增加的距离的平方,由图所示,D^2(x,y)=16
代码如下:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn = 100;
const int maxv = 1000000;
string a,b;
int n,m;
int dp[maxn][maxn];
int MAX(int x,int y)
{
return x>y?x:y;
}
int MIN(int x,int y)
{
return x<y?x:y;
}
int dtw(int i, int j)
{
if(i>=n || j>=m)
return maxv;
if(dp[i][j]>=0)
return dp[i][j];
dp[i][j] = (a[i]-b[j])*(a[i]-b[j]) + MIN(dtw(i+1,j+1),MIN(dtw(i+1,j),dtw(i,j+1)));
return dp[i][j];
}
int main()
{
a = "ABAC";
b = "DADDAC";
n = a.length();
m = b.length();
memset(dp,-1,sizeof(dp));
dp[n-1][m-1] = (a[n-1]-b[m-1]) * (a[n-1]-b[m-1]);
cout<< dtw(0,0) << endl;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
cout<<dp[i][j]<<" ";
cout<<endl;
}
}