170 likes | 315 Views
习 题课 2. 赵嘉明. 第二次网上作业提交时间: 10.14 24:00. Broken Necklace. 题目大意: 一 串有 N 个珠子 ( N<350) 的项链,珠子可能是红色,蓝色,白色中的一种。在项链中间某一点切断,从一边取下同等颜色的珠子,直到遇上不同的颜色。另一边重复该操作。求出可以收集到最多珠子的数量。 ( 白色可代表任意颜色 ). Broken Necklace. Example:. brrrrwbwwwrwwbbbwrbrrrrbbbbw. A. B. 从 B 处切断:. 从 A 处切断:. 左侧: wwwr.
E N D
习题课 2 赵嘉明
第二次网上作业提交时间: 10.14 24:00
Broken Necklace 题目大意: 一串有N个珠子(N<350)的项链,珠子可能是红色,蓝色,白色中的一种。在项链中间某一点切断,从一边取下同等颜色的珠子,直到遇上不同的颜色。另一边重复该操作。求出可以收集到最多珠子的数量。(白色可代表任意颜色)
Broken Necklace Example: brrrrwbwwwrwwbbbwrbrrrrbbbbw A B 从B处切断: 从A处切断: 左侧:wwwr 左侧:rrrr 右侧:wwbbbw 右侧:bbbbwb
Analysis Q1:如何数出珠子的数量 First:由于白色可以当成任意颜色,我们用一个变量 color记住从断裂处开始第一个不为白色的值。 Second:当再次遇到不是白色,且与color不同的颜色 时,计数停止。
Analysis char color=‘0’; for(int n=0;n<length;++n) {if(color == ‘0' && necklace[i] != 'w') color=necklace[i]; if(color != ‘0' && necklace[i] != 'w' && necklace[i] != color) break;} 将color设置为red Skip 检测到颜色与color不同,退出
动态规划 进一步我们可以发现,统计第N+1个珠子和统计第N个珠子的结果之间有所联系。 我们用red[n]标记从第N个珠子处能取下红色和白色珠子的数量。 用blue[n]标记从第N个珠子处取下蓝色和白色珠子的数量。 brbbwwbrrrw r b w red[n]=4; blue[n]=1; 如果第N+1个珠子是蓝色 • blue(N+1)=blue(N)+1 • red(N)=0 如果第N+1个珠子是白色,那么 red(N+1)=red(N)+1 blue(N+1)=blue(N)+1 如果第N+1个珠子是红色 red(N+1)=red(N)+1 • blue(N+1)=0
动态规划 做为一种寻求最优解的思想,动态规划应用很广,应用动态规划的条件主要是: 因此max(blue(N),red(N))便是我们要的最大值. 原问题可以分解成许多子问题,且原问题和子问题的最优解有关系。
Milking Cows 大意: 给出N个农民,和他们挤牛奶的时间段,求出: 1.最长的时间段(其中至少有一头牛在被挤奶)。 2.最长的时间段(其中没有牛被挤奶)。 考虑到时间段的规模比较小(<1000000) 不会占用太多空间. 因此穷举法是个不错的选择.
Analysis bool time[1000000]={false}; While(fin>>starttime>>finaltime) { for(int n=starttime;n<=finaltime;++n) if(time[n]==false) time[n]=true; } Next step: 求出数组中最长的连续1序列 求出数组中最长的连续0序列 动态规划(dynamic programming)
Dynamic Programming 我们来分析一个复杂一些的动态规划问题: 矩阵链乘法 若A是p×q矩阵,B是q×r矩阵,则AB需要的运算次数为pqr。 按(AB)C的顺序运算. 所需次数为10×100×5+10×5×50=7500次 A:10×100 B:100×5 按A(BC)的顺序运算 所需次数为 100×5×50+10×100×50=75000次 C:5×50
矩阵链乘法 Problem: 如何确定A1A2…An的加括号方式,使总运算次数最小? 设每个矩阵为(ln*rn)形式。 此时应用穷举法复杂度为o(2^n),过于复杂 让我们先来看一下对于i个矩阵,加括号所有的可能性,并用m[i,j]表示Ai到Aj所需最小的运算次数。
矩阵链乘法 当i=1,j=1时,只有一个矩阵A1,显然运算次数为0 m[1,1]=0; 当i=1,j=2时,显然只有一种运算方法A1A2,m[1,2]=l1*l2*r2; 当i=1,j=3时,有两种运算方法: (A1A2)A3 way1=m[3,3]+m[1,2]+l1*r2*r3; A1(A2A3) way2=l1*r1*r3+m[2,3]+m[1,1]; m[1,3]=min{way1,way2};
矩阵链乘法 当i=1,j=n时,我们可以简单的把情况分为 我们可利用长度为1,2,……..n-1的矩阵链的 最小运算次数构造出最终的结果. 而不必用穷举法进行完全列举. 当i=1,j=4时,我们可以把情况分成3种 A1(A2~A4) way1=乘积项+m[2,4]+m[1,1]; (A1A2)(A3A4) way2=乘积项+m[1,2]+m[3,4]; (A1~A3)A4 way3=乘积项+m[1,3]+m[4,4]; 因而 m[1,4]=min{way1,way2,way3}; (A1)(A2~An) (A1A2)(A3~An) (A1A2A3)(A4~An) ………. (A1~An-2)(An-1An) (A1~An-1)(An) 因此。我们只需考虑把矩阵分为两个部分 其余子问题可以通过调用以前的分析解决。 m[i,j]=min{乘积项+m[i,k]+m[k,j]} 其中k>=m,k<=n
伪代码 对于A1A2…An: 我们定义二维数组m[n+1][n+1]={无穷大},表示从Ai到Aj区间内的最优解。 For(i=1~n) m[i,i]=0;(对应只有一个矩阵的情况) For(length=2~n) (对应有两个~N个矩阵的情况) { for(i=1~n+1-length) j=i+length-1;(此处保证了i与j之间有length个矩阵) for(k=i~j-1) way=m[i,k]+m[k+1,j]+乘积项; {if(way<m[i,j]) m[i,j]=way;} }
i 1 2 3 4 5 6 j 6 5 4 3 2 1 For(i=1~n) m[i,i]=0 • Length 2~n • m[i,j]=min{m[i,k]+m[k+1,j]+乘积项;}