思考题15-1

注意到此题是说有向无环图,因此存在动态规划算法计算最长加权简单路径。
设 dis[u]dis[u] 表示从 uu 到 tt 的最长加权简单路径,可以得到如下式子:

dis[u]={0max(u,v)∈E{w(u,v)+dis[v]}if u=totherwise

dis[u]= \begin{cases} 0& \text{if u=t}\\ \max \limits_{(u,v)\in E}\{w(u,v)+dis[v]\} & \text{otherwise} \end{cases}
采用自底向上的方法

LONGEST-PATH(G, s, t)let dist[1...n] and next[1...n] be new arraystopologically sort the vertices of Gfor i = 1 to |G.V| dist[i] = ∞dist[s] = 0for each u in topological order, starting from sfor each edge(u,v)∈ G.Adj[u]if dist[u] + w(u,v) > dist[v] dist[v]  = dist[u] + w(u,v)next[u] = v
print “The longest distance is ” dist[t] 
PRINT-PATH(s, t, next)

时间复杂度是 Θ(V+E)\Theta(V+E)。

思考题15-2

首先说一下,这题和一般的最长回文子序列好像不一样,因为它给的 character 得到的是 carac,这个子串在原字符串中并不连续,一般的应该返回是 ara。
针对这题,很简单的一个思路就是求最长公共子序列,先把字符串逆转,然后求最长公共子序列就可以了。

#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;void LCS_LENGTH(string &x,string &y,int **b,int **c)
{int m = x.size(),n = y.size();for(int i = 0; i <= n; i++)c[i][0] = 0;for(int i = 1; i <= n; i++)c[0][i] = 0;for(int i = 1; i <= m; i++){for(int j = 1; j <= n; j++){if(x[i-1] == y[j-1]){c[i][j] = c[i-1][j-1] + 1;b[i][j] = 0;}else if(c[i-1][j] >= c[i][j-1]){c[i][j] = c[i-1][j];b[i][j] = 1;//up}else{c[i][j] = c[i][j-1];b[i][j] = 2;//left}}}
}void PRINT_LCS(int **b,string &x,int i,int j)
{if(i == 0 || j == 0)return;if(b[i][j] == 0){PRINT_LCS(b,x,i-1,j-1);cout << x[i-1];}else if(b[i][j] == 1)PRINT_LCS(b,x,i-1,j);else PRINT_LCS(b,x,i,j-1);
}int main()
{string x = "character";string y = x;for(int i = 0; i < y.size()/2; i++){char temp = y[i];y[i]  = y[y.size() - i - 1];y[y.size() - i - 1] = temp;}int m = x.size(),n = y.size();int **b = new int *[m+1];int **c = new int *[m+1];for(int i = 0; i <= m; i++){b[i] = new int[n+1];c[i] = new int[n+1];}LCS_LENGTH(x,y,b,c);PRINT_LCS(b,x,m,n);cout << endl;for(int i = 0; i <= m; i++){delete []b[i];delete []c[i];}delete []b;delete []c;return 0;
}

思考题15-3

首先按照 x 坐标进行排序,需要 O(nlgn)O(n\lg n) 时间,设排序后的点从左到右为 (p1,p2...pn)(p_1,p_2...p_n),其中 p1p_1 是最左点, pnp_n 是最右点。
定义双调路径 Pi,j,其中i≤jP_{i,j},其中i\le j,包含所有的 p1,p2...pjp_1,p_2...p_j。从 pip_i 开始,严格的左走到 p1p_1,然后严格的右走到 pjp_j。记 pi,pjp_i,p_j 两点的欧氏距离为 |pipj||p_ip_j|,记 b[i,j],其中1≤i≤j≤nb[i,j],其中 1\le i\le j\le n,为双调路径 Pi,jP_{i,j} 的最短路径。
我们有下面的 b[i,j]b[i,j] 式子,其中 1≤i≤j≤n1\le i\le j\le n:

b[1,2]=|p1p2|b[i,j]=b[i,j−1]+|pj−1pj|,其中i<j−1b[j−1,j]=min1≤k<j−1{b[k,j−1]+|pkpj|}

b[1,2]=|p_1p_2|\\b[i,j]=b[i,j-1]+|p_{j-1}p_j|,其中 i
我们需要计算 b[n,n]=b[n−1,n]+|pn−1pn|b[n,n]=b[n-1,n]+|p_{n-1}p_n|,同时定义一个 r[i,j]r[i,j] 来记录最短双调路径 Pi,jP_{i,j} 中 pjp_j 相邻连接点的下标。

EUCLIDEAN-TSP(p)sort the points so that <p1, p2, p3...pn> are in order of increasing x-coordinatelet b[1...n,2...n] and r[1...n-2,3...n] be new arraysb[1,2] = |p1p2|for j = 3 to nfor i = 1 to j - 2b[i,j] = b[i,j-1] + |pj-1pj|r[i, j]  = j - 1b[j-1,j] = ∞for k = 1 to j - 2q = b[k, j-1] + |pkpj|if q < b[j-1, j] b[j-1,j] = qr[j-1,j] = kb[n,n] = b[n-1, n] + |pn-1pn|return b and r

然后从 pnp_n 沿着包含 pn−1p_{n-1} 的向左打印,直到 p1p_1,然后向右打印剩余的点(不包括 pn−1p_{n-1})

PRINT-TOUR(r, n)print pnprint pn-1k = r[n-1, n]PRINT-PATH(r, k, n-1)print pkPRINT-PATH(r, i, j)if i < jk = r[i, j]if k ≠ iprint pkif k > 1PRINT-PATH(r, i, k)else k = r[j,i]if k > 1PRINT-PATH(r, k, j)print pk

在调用PRINT-PATH时,当 i<ji 表示从右向左的路径,当 i>ji>j则是从左到右的路径。
最后总的时间复杂度是 O(n2)O(n^2)。

思考题15-4

先假设最长的单词长度小于 MM。
定义 extra[i,j]=M−j+i−∑k=ijlkextra[i,j]=M-j+i-\sum \limits_{k=i}^{j}l_k 表示包含单词 ii 到单词 jj 的这一行的额外空格数,注意 extra[i,j]extra[i,j] 可能是负数。接着定义包含单词 ii 到单词 jj 的这一行的代价 lclc:

lc[i,j]=⎧⎩⎨⎪⎪∞0(extra[i,j])3当 extra[i,j]<0当j=n并且extra[i,j]≥0(即最后一行)otherwise

lc[i,j]= \begin{cases} ∞& \text{当 extra[i,j]
定义 c[j]c[j] 是一个最优排列的单词 1,2,...j1,2,...j 的代价,假设某一行以单词 ii 开始到单词 jj 结束,则 c[j]=c[i−1]+lc[i,j]c[j]=c[i-1]+lc[i,j]。其中 c[0]=0,c[1]=lc[1,1]c[0]=0,c[1]=lc[1,1]。然后有:

c[j]={0min1≤i≤j{c[i−1]+lc[i,j]}当 j=0当 j>0

c[j]= \begin{cases} 0& \text{当 j=0}\\ \min \limits_{1\le i\le j}\{c[i-1]+lc[i,j]\} & \text{当 j>0} \end{cases}
还需要计算一个表 pp 。当 c[j]c[j] 计算出来后,若 c[j]=c[k−1]+lc[k,j]c[j]=c[k-1]+lc[k,j],则 p[j]=kp[j]=k,表示最后一行是以单词 kk 开头到单词 jj 结尾。计算的伪代码如下:

PRINT-NEATLY(l, n, M)let extra[1..n, 1..n], lc[1..n, 1..n], and c[0..n] be new arrays// Compute extra[i, j]  for 1 ≤i ≤j ≤n.for i = 1 to nextra[i, i]  = M-lifor j = i + 1 to nextra[i, j]  = extra[i, j-1]-lj-1// Compute lc[i, j]  for 1 ≤i≤ j≤n.for i = 1 to nfor j = i to nif extra[i, j]  < 0lc[i, j] = ∞ elseif j == n and extra[i, j] ≥ 0lc[i, j] = 0else lc[i, j]  = (extra[i, j])^3// Compute c[j]  and p[j]  for 1 ≤j≤ n.c[0] = 0for j = 1 to nc[j]  = ∞for i = 1 to jif c[i-1] + lc[i, j]  < c[j]c[j] = c[i-1] + lc[i, j] p[j] = ireturn c and p

显然时间和空间复杂度都是 O(n2)O(n^2),实际上可以减少时间和空间复杂度,我们知道每个单词长度必定大于等于1,并且每个单词后面有一个空格,所以一行最多可以有 ⌈M/2⌉\lceil M/2\rceil 个单词。对于一行有 j−i+1j-i+1 个单词来说,若 j−i+1>⌈M/2⌉j-i+1>\lceil M/2\rceil ,则 lc[i,j]=∞lc[i,j]=\infty,因此我们只需要计算和存储 j−i+1≤⌈M/2⌉j-i+1\le \lceil M/2\rceil 的 extra[i,j]extra[i,j] 和 lc[i,j]lc[i,j]。这样计算 c[j],p[j]c[j],p[j] 时为 max(1,j−⌈M/2⌉+1) to j\max (1,j-\lceil M/2\rceil +1)\ to\ j。当然还可以把空间降到 Θ(n)\Theta(n)。
最后是打印哪个单词在哪一行,GIVE-LINES(p,j) 打印一个三元组(k,i,j),即单词 ii 到 单词 jj 在第 kk 行,最后函数返回行数 kk。

GIVE-LINES(p, j)i = p[j] if i == 1k = 1else k = GIVE-LINES(p, i-1) + 1print(k, i, j)return k

对应的代码如下:

#include <iostream>
#include <string>
#include <algorithm>
using std::cout;
using std::cin;
using std::endl;
using std::string;void PRINT_NEATLY(int *l,int n,int M,int *c,int *p)
{int **extra = new int *[n];int **lc = new int *[n];for(int i = 0; i < n; i++){extra[i] = new int[n];lc[i] = new int[n];}for(int i = 0; i < n; i++){extra[i][i] = M - l[i];for(int j = i + 1; j < n; j++)extra[i][j] = extra[i][j-1] - l[j] - 1;}for(int i = 0; i < n; i++){for(int j = i; j < n; j++){if(extra[i][j] < 0)lc[i][j] = INT_MAX/2;//这里做个特别处理是为了防止后面c[i]>c[j-1]+lc[j-1][i-1]溢出else if(j == n - 1 && extra[i][j] >= 0)lc[i][j] = 0;else lc[i][j] = pow(static_cast<double>(extra[i][j]),3);}}c[0] = 0;for(int i = 1; i <= n; i++){c[i] = INT_MAX;for(int j = 1; j <= i; j++){if(c[i] > c[j-1] + lc[j-1][i-1]){c[i] = c[j-1] + lc[j-1][i-1];p[i] = j;}}}for(int i = 0; i < n; i++){delete []extra[i];delete []lc[i];}delete []extra;delete []lc;
}int GIVE_LINES(int *p,int j)
{int i = p[j];int k;if(i == 1)k = 1;else k = GIVE_LINES(p,i-1) + 1;cout <<"第 " << k << " 行," << "第 " << i << " 个单词到第 " << j << " 个单词" << endl;return k;
}int main()
{int l[] = {3,7,2,5,1,8,5,1,4};//一共9个单词int *c = new int[10];int *p = new int[10];int M = 10;//每行的最多有 M 个字符PRINT_NEATLY(l,9,M,c,p);GIVE_LINES(p,9);delete []c;delete []p;return 0;
}

CLRS第十五章思考题1-4相关推荐

  1. CLRS第十五章思考题9-12

    思考题15-9 首先我们在 LL 表的最前和最后面分别加上 00 和 nn,然后将 LL 表按照升序排列.记 L[i...j]L[i...j] 为 LL 中从下标 ii 到 jj.定义子问题 (i,j ...

  2. CLRS第十四章思考题

    思考题14-1 a) 设最大重叠点不是重叠区间的任意一个区间的端点.令 pp 是最大重叠区间为 mm 段区间的一个点,但不是重叠区间的任何一个区间的端点.又设 p′p' 是和 mm 段区间重叠的一个端 ...

  3. 《算法导论3rd第十五章》动态规划

    前言 和分治法一样, 动态规划 (dynamic programming)是通过组合子问题的解而解决整个问题的.分治法是将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原问题 ...

  4. java十五章_java:第十五章

    第十五章 字符串1.字符串(String)的定义 String str="内容"; String str=new String(); //内容为null String str=ne ...

  5. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引...

    Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引 原文:Introduction to 3 ...

  6. Gradle 1.12用户指南翻译——第三十五章. Sonar 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  7. Visual C++ 2008入门经典 第十五章 在窗口中绘图

    /*第十五章 在窗口中绘图 主要内容: 1 Windows为窗口绘图提供的坐标系统 2 设置环境及其必要性 3 程序如何以及在窗口中绘图 4 如何定义鼠标消息的处理程序 5 如何定义自己的形状类 6 ...

  8. 第十五章 shell正则表达式

    第十五章 shell正则表达式 见图片 Shell正则表达式 正则表达式的分类 基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs) 扩展的正 ...

  9. 第二十五章补充内容 3 assert()宏

    //第二十五章补充内容 3 assert()宏 //有的编译器还提供了assert()宏,这个宏在许多书中被翻译为断言,它的作用是当assert()的参数为真时,返回真,假如参数值为假,那么它将执行某 ...

最新文章

  1. 静态路由和默认路由的区别
  2. C/C++结构体的区别
  3. LINUX自旋锁详解
  4. 把企业分“三只鸟”的发展好比“三个策略”
  5. python processpoolexector 释放内存_一起看看python 中日志异步发送到远程服务器
  6. verilog的$dumpfile和$dumpvar系统任务详解
  7. HDU - 4333 Revolving Digits(扩展KMP)
  8. python设计大赛_GitHub - FatBallFish/Multimedia-Python: 多媒体设计大赛-Python后端
  9. java字符的输入流_Java:字节流和字符流(输入流和输出流)
  10. mysql 不省略0_mysql数据类型和运算符
  11. Java中Integer类型的整数值的大小比较
  12. 移动硬盘(U盘)病毒对数据的破坏
  13. 抓住“智慧城市”的机遇
  14. Arcpy基础入门-1、如何使用arcpy
  15. 【螺钉和螺母问题】【算法分析与设计】假设我们有n个直径各不相同的螺钉以及n个相应的螺母...
  16. coco2017数据集百度网盘链接
  17. Google谷歌关键词监控系统
  18. 格林尼治时间与本地时间的转换
  19. OTA线下攻防战 | 一点财经
  20. 服务器开机显示b7,服务器启动B7提示

热门文章

  1. matlab提取语音信号基频检测,语音信号处理中基频提取算法综述
  2. Android Toast连续快速切换更新内容无延迟
  3. 默克尔树 Merkle Tree
  4. html中怎么固定一张图片大小,固定大小的div,不固定大小的图片如何放入div?
  5. C++轻量级跨平台桌面GUI库FLTK的简单使用
  6. 【PMP】PMBOK 笔记 第2章 组织影响和项目生命周期
  7. STM32CubeIDE界面设置为黑色
  8. PHP代码的执行的过程
  9. PHP源码分析(内存管理)
  10. 使用PCA9685控制多个舵机