分治算法的基本思想的是将一个规模为N的问题分解为K个规模较小的问题,这些子问题是相互独立且与原问题性质相同的
例1-1计数问题
给定2个数a,b计算出1在a和b之间出现的次数
算法思想:
计算出1在0-a和0-b之间出现的次数,然后相减
例如在计算0-197之间的数
1.首先计算190-197之间个位数上出现1的次数
2.然后计算180-189上的1出现的个数
3然后递归 到18求解 权值*10
源代码如下:
#include<stdio.h> #define N 10 int count[N]; int value=1; void Deal(int k) { if(k<=0)return; int one,ten; one=k%10; k/=10; ten=k; for(int i=0;i<=one;i++) //第一步 { count[i]+=value; } while(ten) //第一步 { count[ten%10]+=value*(one+1); ten/=10; } for(int j=0;j<10;j++) //第二步 { count[j]+=value*k; } count[0]-=value; value*=10; //第三步 Deal(k-1); //第三步 } int main() { int a,b; while(scanf("%d%d",&a,&b)!=EOF) { for(int i=0;i<10;i++) count[i]=0; value=1; Deal(b); value=-1; Deal(a-1); printf("%d\n",count[1]); } return 0; }
例1-2整数划分问题
在整数划分的问题中,可以采取递归的方式解决,也可以采取剪枝搜索的方式解决,最好的还是采动态规划的方式解决
搜索剪枝的代码:
int fun(int n,int k) { if(n<k)return 0; if(n==k)return 1; int sum=1; for(int i=n-1;i>=n/2;i--) { if(i>=k&&(n-i)>=k) sum+=fun(i,n-i); } return sum; }
动态规划的代码:
void Dp(int n) { int i,j; for(i=0;i<=n;i++) { A[i][1]=1; } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(j>i)A[i][j]=A[i][i]; if(j==i)A[i][j]=1+A[i][i-1]; if(i>j)A[i][j]=A[i][j-1]+A[i-j][j]; } } printf("Dp res is %d\n",A[n][n]); }