【挑战程序设计竞赛】 递归与分治算法


将问题分解,通过求解局部性的小问题来解决原本的问题,这种技巧称为分治法。
实现分治法需要用到递归。
使用递归的技巧,可以将一个问题拆分成两个或更多较小的局部问题,利用递归函数求每个局部问题的解,然后再将整个结果整合,最终解决问题。
分治法

  • 将问题“分割”成局部问题
  • 递归地求解局部问题
  • 将局部问题的解“整合”,解决原问题。

穷举搜索

题目

现有长度为n的数列A和整数m。请编写一个程序,判断A中任意几个元素相加是否能得到m。A中每个元素只能使用一次。
数列A以及用作问题的q个mi由外界输入,对每个问题输出yes或no。

思路

可以将所有数列组合都列出来,每个元素都有“选”或者“不选”两个选项。
solve(i,m)就可以分为solve(i+1,m)和solve(i+1,m-A[i])这两个局部问题。(其中m-A[i]表示“使用第i个元素”)。
在这里插入图片描述

代码

#include <stdio.h>

int n,A[50];

/*从输入值M中减去所选元素的递归函数*/
int solve(int i,int m){
	if(m==0) return 1;
	if(i>=n) return 0;
	int res= solve(i+1,m) || solve(i+1,m-A[i]);
	return res;
} 
int main(){
	int q,M,i;
	
	scanf("%d",&n);//长度n 
	for(i=0;i<n;i++) scanf("%d",&A[i]);//数组A 
	scanf("%d",&q);//整数M的个数 
	for(i=0;i<q;i++){
		scanf("%d",&M);//整数M 
		if(solve(0,M)) printf("yes\n");
		else printf("no\n");
	}
	
	return 0;
}

科赫曲线

题目

编写一个程序,输入整数n,输出科赫曲线的顶点坐标,该科赫曲线由深度为n的递归调用画出。
在这里插入图片描述

思路

koch包含三个参数,分别是递归深度d,以及线段的两个端点p1、p2。这个递归函数首先会求出线段p1p2的三等分点s、t,然后求能够使得线段su、ut、ts组成的正三角的点u。接下来处理一下函数,从而描绘出图形:

  1. 对线段p1s递归调用koch,输出s的坐标。
  2. 对线段su递归调用koch,输出u的坐标。
  3. 对线段ut递归调用koch,输出t的坐标。
  4. 对线段tp2递归调用koch。

s与t的坐标可通过一下公式计算出来:
s.x=(2p1.x+1p2.x)/3
s.y=(2p1.y+1p2.y)/3
t.x=(1p1.x+2p2.x)/3
t.y=(1p1.y+2p2.y)/3

以点s为起点,将点t逆时针旋转60度,可得到u。
u.x=(t.x-s.x)*cos60°-(t.y-s.y)*sin60°+s.x
u.y=(t.x-s.x)*sin60°-(t.y-s.y)*cos60°+s.y

代码

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;

struct Point{
	double x;
	double y;
};

void koch(int n,Point a,Point b){
	if(n==0) return;
	
	Point s,t,u;
	double th=M_PI*60.0/180.0;//将单位从度变为弧度
	
	s.x=(2.0*a.x+1.0*b.x)/3.0;
    s.y=(2.0*a.y+1.0*b.y)/3.0;
    t.x=(1.0*a.x+2.0*b.x)/3.0;
    t.y=(1.0*a.y+2.0*b.y)/3.0;
    
    u.x=(t.x-s.x)*cos(th)-(t.y-s.y)*sin(th)+s.x;
    u.y=(t.x-s.x)*sin(th)+(t.y-s.y)*cos(th)+s.y;
    
    koch(n-1,a,s);
    printf("%.8f %8.f\n",s.x,s.y);
    koch(n-1,s,u);
    printf("%.8f %8.f\n",u.x,u.y);
    koch(n-1,u,t);
    printf("%.8f %8.f\n",t.x,t.y);
    koch(n-1,t,b);
}

int main(){
	Point a,b;
	int n;
	
	scanf("%d",&n);
	
	a.x=0;
	a.y=0;
	b.x=100;
	b.y=0;
	
	printf("%.8f %.8f\n",a.x,a.y);
	koch(n,a,b);
	printf("%.8f %.8f\n",b.x,b.y);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值