算法课10-dynamic programming III

String similarity

如何衡量两个字符串的相似度?
引入edit distance的概念 δ + α p , q \delta + \alpha_{p,q} δ+αp,q gap+mismatch 即,
填充一个空格或者把pq对应位置的字母换成一致,最终使得两个字符串达到一致
需要最小化这个距离
算法课10-dynamic programming III_第1张图片

Hirschberg算法可将空间压缩到 θ ( m + n ) \theta(m+n) θ(m+n)

单汇最短路径

【这里复习一下dijkstra算法 贪心在图中的应用】
当有负边的时候,dijkstra不管用了
Bellman Ford算法 解决图中有负边的最短路径问题
算法课10-dynamic programming III_第2张图片

算法课10-dynamic programming III_第3张图片
注意:里面两层for循环加起来的时间复杂度是 θ ( m ) \theta(m) θ(m)
总的时间复杂度是 θ ( n m ) \theta(nm) θ(nm)
画出依赖关系图可知,每行只依赖于前一行,空间压缩可以将i这一维压缩
用d(v)目前表示v~t的最短路径大小
算法课10-dynamic programming III_第4张图片
点的遍历顺序不重要,若d(w)上一轮没有更新,则在下一轮也不用更新了,所有的d(v)都不变,整个算法终止。
在循环i次时,d(v)是v~t用i条边到达的一个下界,
若循环到n轮,仍有值发生改变,说明有负环。

// The main function that finds shortest distances from src to 
// all other vertices using Bellman-Ford algorithm.  The function 
// also detects negative weight cycle 
void BellmanFord(struct Graph* graph, int src) 
{ 
    int V = graph->V; 
    int E = graph->E; 
    int dist[V]; 
  
    // Step 1: Initialize distances from src to all other vertices 
    // as INFINITE 
    for (int i = 0; i < V; i++) 
        dist[i]   = INT_MAX; 
    dist[src] = 0; 
  
    // Step 2: Relax all edges |V| - 1 times. A simple shortest  
    // path from src to any other vertex can have at-most |V| - 1  
    // edges 
    for (int i = 1; i <= V-1; i++) 
    { 
        for (int j = 0; j < E; j++) 
        { 
            int u = graph->edge[j].src; 
            int v = graph->edge[j].dest; 
            int weight = graph->edge[j].weight; 
            if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) 
                dist[v] = dist[u] + weight; 
        } 
    } 
  
    // Step 3: check for negative-weight cycles.  The above step  
    // guarantees shortest distances if graph doesn't contain  
    // negative weight cycle.  If we get a shorter path, then there 
    // is a cycle. 
    for (int i = 0; i < E; i++) 
    { 
        int u = graph->edge[i].src; 
        int v = graph->edge[i].dest; 
        int weight = graph->edge[i].weight; 
        if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) 
            printf("Graph contains negative weight cycle"); 
    } 
  
    printArr(dist, V); 
  
    return; 
} 

负环检测

使用Bellman Ford算法进行检测,在第n轮更新时有OPT(n,v)改变,则有负环(负环路径上的点的值不一定改变,但是一定会有一个改变的)

Shortest Path Fast Algo (SPFA) Bellman Ford的队列实现
算法大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。

使用一个队列,每次将顶点前继节点加入队列,队列中的点的值要进行更新
一个点在将要加入队列时,可能已经在队列中,要防止加入队列两次
检测负环:一个点进入队列n次,则有负环

const int INF = 999999;
int  map[MAXN][MAXN]; //map[i,j]为初始输入的i到j的距离,未知的map[i,j]=INF;
int  dis[MAXN];
char vst[MAXN];
// 参数n表示结点数,s表示源点
int SPFA(int n, int s)
{
	// pri是队列头结点,end是队列尾结点
    int i, pri, end, p, t;
    memset(vst, 0, sizeof(vst));
    for(int i=0; i<MAXN; ++i)
        Q[i] = 0;
    for (i=0; i<n; i++)
        dis[i] = INF;
    dis[s] = 0;
    vst[s] = 1;
    Q[0] = s; pri = 0; end = 1;
    while (pri < end)
    {
        p = Q[pri];
        for (i=0; i<n; ++i)
        {
			//更新dis
            if (dis[p]+map[p][i] < dis[i])
            {
                dis[i] = dis[p]+map[p][i];
                if (!vst[i])     //未在队列中
                {
                    Q[end++] = i;
                    vst[i] = 1;
                }
            }
        }
        vst[p] = 0;   // 置出队的点为未标记
        pri++;
    }
    return 1;
}

LeetCode 练习
Cheapest flights within k stops
Network delay time

你可能感兴趣的:(数据结构,LeetCode)