Problem Set 1

Problem Set 1.1

Problem 1.1.1

1)
基本情况:若z=0,则yz=0,返回正确值
归纳假设:令d为一个常数,假设z<d,算法返回正确值
归纳步骤:若z=d,利用数学归纳法

  • z为偶数,则返回INT-MULT(2y,z2),由于函数的第二个参数变小了,根据数学归纳法,有INT-MULT(2y,z2)=2yz2=yz,返回正确值
  • z为奇数,则返回INT-MULT(2y,z12)+y,由于函数的第二个参数变小了,根据数学归纳法,有INT-MULT(2y,z12)+y=2yz12+y=yz,返回正确值

2)
基本情况:若z=0,则yz=0,返回正确值
归纳假设:令d为一个常数,假设z<d,算法返回正确值
归纳步骤:若z=d,利用数学归纳法。设z mod c=r,则返回INT-MULT(cy,zrc)+ry=yz,返回正确值

Problem 1.1.2

由代码有T(n)=n/4n10+2(n/2n/4)n20+3n/4n/22n30+n3n/42nn=16.25+n8

Problem 1.1.3

1)
U={1,2,3,4},S={{1,2,3},{4},{1,2}}
可知算法会选择会选择S的所有元素,但实际上只用选择两个元素即可
2)
使用深度优先搜索,考察S中每个元素是否选,一共有2m种选择,将这些选择全部检查一遍,从符合题意的组合中选择组合包含元素个数最少的即可。由于覆盖了所有可能的情况,如果问题有解,那么肯定可以找出最小覆盖,也就是说算法是正确的。代码如下

void work(int step,int cnt)
//step表示当前正在选择第step个集合 
//cnt表示已经选择的集合个数 
{
	if(step==m+1)
	{
		//now表示选择了的集合的并集
		//ans表示最小覆盖数 
		if(now.size()==n) ans=min(ans,cnt);
		return;
	}
	work(step+1,cnt);
	set<int> now_copy=now;
	for(set<int>::iterator it=s[step].begin();it!=s[step].end();++it) 
	now.insert(*it);
	work(step+1,cnt+1);
	now=now_copy;
}

3)
能,除非问题无解,比如令U={1,2},S={{1}}

Problem 1.1.4

以下代码均忽略数值溢出的问题
1)

int work(int T)//设S是全局变量,找到了返回最后一个被扫描到的硬币的下标,未找到返回0
{
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=s[i];
		if(sum==T) return i;
	}
	return 0;
 } 

反例:S={1,2,3,4,5},T=4
2)

int work(int T)//设S是全局变量,找到了返回最后一个被扫描到的硬币的下标,未找到返回0
{
	sort(s+1,s+n+1);
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=s[i];
		if(sum==T) return i;
	}
	return 0;
 } 

反例同1)
3)

int work(int T)//设S是全局变量,找到了返回最后一个被扫描到的硬币的下标,未找到返回0
{
	sort(s+1,s+n+1,greater<int>());
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=s[i];
		if(sum==T) return i;
	}
	return 0;
 } 

反例同1)

Problem Set 1.2

Problem 1.2.1

1)
利用数学归纳法证明。
基本情况:有F1=F2=1,F3=2,可知,对于前三个数符合题意
归纳假设:设对前n个数符合题意(不妨设n3的倍数)
归纳步骤:由于Fn+1=Fn+Fn1,而偶数加奇数为奇数,所以Fn+1为奇数,同理有Fn+2=Fn+1+Fn为奇数;有Fn+3=Fn+1+Fn+2,而奇数加奇数为偶数,所以Fn+3为偶数。由于n3的倍数,所以n+1,n+2不能被3整除而n+3可以,所以对于前n+3个数符合题意
2)
利用数学归纳法证明。
基本情况:对于F1,F2,显然符合上述公式
归纳假设:假设对于前n1个数符合上述公式
归纳步骤:要证明Fn2Fn+1Fn1=(1)(n+1),只用证明Fn2(Fn+Fn1)Fn1=(1)(n+1),而

Fn2(Fn+Fn1)Fn1=(Fn12(Fn1+Fn2)Fn2)=(1)(n+1)

证毕

Problem 1.2.2

1)
直接证明2)
2)
在二叉树中,有边数=总结点个数1
而边数又等于子节点个数,所以子节点个数等于总结点个数1
在这道题目中,即n1+2n2=n0+n1+n21
化简即n0=n2+1

Problem 1.2.3

我认为题干的符号可能使用的不是很正确,像O这种符号都表示一个集合,而题干却让一个函数等于了一个集合,应该不是题目的意思,所以我认为等号应该换成,下面仍然使用等号,但是表达的意思
1)

  • O:若 f=O(g),则存在 c1,n1 使得当 nn1 时,f(n)c1g(n)。若 g=O(h),则存在 c2,n2 使得当 nn2 时,g(n)c2h(n)。取 n0=max(n1,n2),当 nn0 时,f(n)c1c2h(n),即 f=O(h)
  • Ω:类似 O,方向相反
  • Θ:结合 O 和 Ω 的传递性,存在常数使得上下界同时传递
  • o:若 f=o(g),则 limnf(n)g(n)=0。若 g=o(h),则 limng(n)h(n)=0。故 f(n)h(n)=f(n)g(n)g(n)h(n)0,即 f=o(h)
  • ω:类似 o,极限趋向于无穷大,乘积仍趋向无穷大

2)

  • O:取 c=1,则 f(n)1f(n),故 f=O(f)
  • Ω:同理,f(n)1f(n),故 f=Ω(f)
  • Θ:由 O 和 Ω 自反性,得 f=Θ(f)

3)

  • 自反性:已证
  • 对称性:若 f=Θ(g),则存在 c1,c2>0 使得 c1g(n)f(n)c2g(n),从而 1c2f(n)g(n)1c1f(n),即 g=Θ(f)
  • 传递性:已证

综上,Θ 是等价关系

4)
f=Θ(g)f=O(g)Ω(g)f=O(g),f=Ω(g)

5)

  • O与Ω:f=O(g)c>0,f(n)cg(n)g(n)1cf(n)g=Ω(f)
  • o与ω:f=o(g)limnf(n)g(n)=0limng(n)f(n)=g=ω(f)

6)

  • o(g) ∩ ω(g) = ∅:若 ho(g),则 limnh(n)g(n)=0,但若 hω(g),则 limnh(n)g(n)=,矛盾
  • Θ(g) ∩ o(g) = ∅:若 hΘ(g),则 c>0 使得 h(n)cg(n),但 ho(g) 要求 h(n)ϵg(n) 对所有 ϵ>0,矛盾
  • Θ(g) ∩ ω(g) = ∅:类似上一条

Problem 1.2.4

下面的小于符号和等于符号都代表渐进复杂度
1)
直接做2)
2)

loglogn<logn<log2n<n<n<nlogn<n1+ϵ<n2=n2+logn<n3

<nn3+7n5<2n1=2n<en<n!

Problem Set 1.3

Problem 1.3.1

第二个是正确的。对n=1,2显然成立
假设对前n1项成立,那么F(n)=F(n1)+F(n2)0.01(32)n1+0.01(32)n2=0.01(32)n2520.01(32)n
第一个是不正确的,类似上面的正面,有5294,这显然是不对的

Problem 1.3.2

a.
a=2,b=3,f(n)=1,根据主定理,ϵ,f(n)O(nlogbaϵ),所以T(n)Θ(nlogba)
b.
T(n)=clogn+clogn2+clogn4+...+clog1=clognk=0lognkΘ(log2n)(用递归树也可以得到相同结果)
c.
a=1,b=2,f(n)=cn,根据主定理,ϵ,f(n)Ω(nlogba+ϵ),且有f(n/2)34f(n),所以T(n)Θ(n)
d.
a=2,b=2,f(n)=cn,根据主定理,f(n)Θ(nlogba),所以T(n)Θ(nlogn)
e.
T(n)=cnlogn+2cn2logn2+4cn4logn4+...+nclog1=cnlognk=0lognkΘ(nlog2n)
f.
用递归树进行计算,如下
image
可以知道每一层的计算量都为O(n),一共有O(logn)层,所以复杂度为O(nlogn)
g.
利用递归树分析。对于第一层,总耗费为O(n);对于第二层,总耗费为O((a1+a2+...+ak)n);对于第三层,总耗费为O((a1+a2+...+ak)2n);依此类推。由于a1+a2+...+ak<1,所以T(n)=O(n)i=0(a1+a2+...+ak)i=O(n)
也可以用代入法做,而且得出的结论更强。
假设T(n)dn,代入递归式得T(n)d(a1+a2+...+ak)n+cn;要让d(a1+a2+...+ak)n+cndn,只需取dc1(a1+a2+...+ak),所以T(n)O(n);同理可证T(n)Ω(n);所以T(n)Θ(n)

Problem 1.3.3

仍然使用递归树分析,将nT(n)看做nT(n)相加,可以知道每层的计算复杂度为nO(n)=O(n),层数为n可以开根号的次数,设为m,则时间复杂度为O(mn).m是一个很小的数,对于百万级别的数据来说,m不会超过10,所以甚至可以视为一个常数
另外一种做法:T(n)=nT(n)+n=n(nT(n)+n)+n=n3/4T(n1/4)+2n
继续展开可以得到类似结论

Problem 1.3.4

(a)
最终的矩阵一共有四个元素,每个元素都是经过两次乘法运算和一次加法运算得到的,所以一共会经过八次乘法运算和四次加法运算;根据递推,不难得到,如果不使用矩阵快速幂而是使用O(n)的乘法的话,会经过8(n1)次乘法运算
(b)
这个使用矩阵快速幂即可,数学原理是矩阵乘法满足结合律,代码见下

void mul(arr x,arr y)
{
    ll z[1][2];
	memset(z,0,sizeof(z));
	for(int i=0;i<=0;i++)
	for(int j=0;j<=1;j++)
	for(int k=0;k<=1;k++)
	z[i][j]=(z[i][j]+x[i][k]*y[k][j])%p;
	memcpy(x,z,sizeof(z));
}
void mulself(arr x,arr y)
{
    ll z[2][2];
	memset(z,0,sizeof(z));
	for(int i=0;i<=1;i++)
	for(int j=0;j<=1;j++)
	for(int k=0;k<=1;k++)
	z[i][j]=(z[i][j]+x[i][k]*y[k][j])%p;
	memcpy(x,z,sizeof(z));
}
int main()
{
		n=read();
		ans[0][0]=0,ans[0][1]=1;
		ll A[2][2]={{0,1},{1,1}};
		while(n)
		{
			if(n&1) mul(ans,A);
			mulself(A,A);
			n>>=1;
		}
		printf("%lld\n",ans[0][0]);
    return 0;
}

(c)
要计算中间结果都是O(n)位长的,由于数列中的数都是正数,所以矩阵快速幂中间的矩阵的元素值不会比数列中的某些值大,所以只用证明F(n)的长度是O(n)的即可,即证明log10F(n)O(n).根据特征方程可以计算出F(n)的通项公式为ϕn5,于是不难证明
(d)
我们已经证明了会有O(logn)次矩阵乘法,而每次矩阵乘法的复杂度为M(n)=O(n2)(由(c),中间结果不会超过O(n)位),所以总的时间复杂度是O(M(n)logn)
(e)
由提示,我们真正的复杂度其实是O(12)+O(22)+O(42)+O(82)+...+O(n2)O(n2),得证

posted @   最爱丁珰  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示