• 蓝桥杯之分治法与动态规划


    [6.1 二分查找]

    已知有序的序列 int[] a,
    整数 x
    要求找到一个刚好比x稍微大一点的元素位置

    思路:
    磁体会进行递归,但是不是所有情况都递归,比如,我们只从每次结果中选出x所在范围再进行递归,这样会减少许多操作步骤,最后一步时,我们只有一个数字,如果这个数字比x大,那么这个数字的下标就是答案,否则,就是这个数字后面那个数字对应的下标。

    代码:
    #include<cstdio>
    
    int f(int a[],int x,int begin,int end){
    	
    	if(begin+1==end) {
    		if(a[begin]>x) return begin;
    		return end;
    	}
    	
    	int k=(begin+end)/2;
    	if(x>=a[k]){
    		return f(a,x,k,end);
    	}
    	return f(a,x,0,k);
    }
    
    int g(int a[],int x,int len){
    	if(x>a[len-1]) return -1;
    	return f(a,x,0,len);
    }
    
    int main(){	
    	freopen("data.in","r",stdin);
    	int a[1000],i=0;	
    
    	while(scanf("%d",&a[i++])!=EOF);
    	
    	i--;
    	int r = g(a,32,i);
    	printf("%d",r);
    }
    --------------------------------------

    [6.2 最大连续部分和]

    数组中整数有正有负
    求连续一子段,使得和最大化
    2,4,-7,5,2,-1,2,-4,3
    最大连续段:5,2,-1,2
    最大和为8

    代码:
    #include<cstdio>
    
    int g(int a[],int begin,int end){
    	
    	if(end==begin+1){
    		if(a[begin]>0) return a[begin]; else return 0;
    	}
    	
    	int k=(begin+end)/2;
    	
    	int t1=g(a,begin,k);
    	int t2=g(a,k,end);
    	int t3a=0;
    	int sum=0;
    	for(int i=k-1;i>=begin;i--){
    		sum+=a[i];
    		if(sum>t3a) t3a=sum;
    	}
    	int t3b=0;
    	sum=0;
    	for(int i=k;i<end;i++){
    		sum+=a[i];
    		if(sum>t3b) t3b=sum;
    	}
    	
    	int t3=t3a+t3b;
    	
    	int max=0;
    	if(t1>max) max=t1;
    	if(t2>max) max=t2;
    	if(t3>max) max=t3;
    	
    	
    	return max;
    }
    
    int main(){
    	freopen("data.in","r",stdin);
    	int a[1000],i=0;
    	while(scanf("%d,",&a[i++])!=EOF);
    		
    	i--;
    	printf("%d",g(a,0,i));	
    }
    --------------------------------------

    [6.3 大数乘法]

    multi("5935849584045839123456789","4595805849258430535")



    --------------------------------------

    优化:

    博弈问题:
    #include <cstdio>
    #include<map>
    
    using namespace std;
    
    map<int,int> m;
    
    int fff(int n)
    {
    	if (m.count(n)!=0)
    		return m[n];
    		
    	int t=0;
    
    
    	if (n >= 1 && fff(n - 1) == 0)
    		t=1;
    	if (n >= 3 && fff(n - 3) == 0)
    		t=1;
    	if (n >= 7 && fff(n - 7) == 0)
    		t=1;
    	if (n >= 8 && fff(n - 8) == 0)
    		t=1;
    	
    	if(t){
    		m[n]=1;
    		return 1;
    	}
    	
    	
    	return 0;
    }
    
    int main()
    {	
    	printf("55 : %s
    ",  fff(55) ? "true" : "false");	
    }
    振兴中华:
    #include<cstdio>
    
    int g(int m, int n)
    {
    	if (m == 1 || n == 1) 
    		return 1;
    
    	return (g(m - 1, n) + g(m, n - 1)) % 10000;
    }
    
    int main()
    {
    	int a[100][100]={0};
    	
    	for(int i=1;i<100;i++){
    		a[i][1]=1;
    		a[1][i]=1;
    	}
    	
    	for(int i=2;i<100;i++){
    		for(int j=2;j<100;j++){
    			a[i][j]=(a[i-1][j]+a[i][j-1])%10000;
    		}
    	}
    	
    	printf("%d
    ",a[20][15]);
    	printf("%d
    ",g(20,15));
    }

    --------------------------------------


    [6.4 缓存结果]

    斐波那契 f(n) = f(n-1) + f(n-2)

    解决方法:
    1缓存(按需存放)
    2仔细设计计算次序,可以用数组

    思路:
    用数组存储结果

    代码:
    #include<cstdio>
    
    int main(){
    	int a[10000]={0};
    	a[1]=1;
    	a[2]=1;
    	
    	for(int i=3;i<10000;i++){
    		a[i]=(a[i-1]+a[i-2])%10000007;
    	}
    	
    	int n;
    	scanf("%d",&n);
    	
    	printf("%d
    ",a[n]);
    	
    }
    --------------------------------------

    [6.5 动态规划]

    城墙顶刷漆 

    X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图所示)
    现需要把这些格子刷上保护漆。

    你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)

    比如:a d b c e f 就是合格的刷漆顺序。
    c e f d a b 是另一种合适的方案。

    当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
    输入数据为一个正整数(不大于1000)
    输出数据为一个正整数。

    例如:
    用户输入:
    2
    程序应该输出:
    24

    再例如:
    用户输入:
    3
    程序应该输出:
    96

    再例如:
    用户输入:
    22
    程序应该输出:
    359635897

    思路:
    锦囊:
    fb(n)  从边缘某格开始,到与它相邻的另一个边缘格子结束
    fb(n) = fb(n-1) * 2

    fa(n)  从某个边缘格子开始的所有情况 
    fa(n) = fb(n)      最后走对面格 
        +2*fa(n-1)     第1步走对面格  
    +4*fa(n-2) 第2步走对面格

    通过分析,我们发现,如果从中间的某个格子开始,那么它对面的格子只能等到某一边的格子全部涂完后再涂,因为如果在先走那一边还没涂完的情况下涂了对面格子,那么那一边没有涂的格子就没有机会再涂了。我们先考虑从边缘开始的情况。
    情况1(从边缘开始,到对面格子结束):
    fb(n)=fb(n-1)*2;
    情况2(从边缘开始,不是到对面格子结束):
    fa(n)=fb(i)*fa(n-i)*2+fb(n-i+1)*fa(i-1)*2
    情况3(不从边缘开始,从第i个开始):
    fa(i,n)=fb(i)*fa(n-i)*2+fb(n-i+1)*fa(i-1)*2

    代码:
    #include<cstdio>
    #define M 1000000007
    
    long long fb(int n){
    	if(n==1) return 1;
    	return fb(n-1)*2%M;
    } 
    
    long long fa(int n){	
    
    
    	if(n==1) return 1;
    	if(n==2) return 6;
    	
    	return (fb(n)+fa(n-1)*2+fa(n-2)*4)%M;
    }
    
    long long fa(int i,int n){
    	
    	return (fb(i)*fa(n-i)*2%M+fb(n-i+1)*fa(i-1)*2%M)*2%M;
    }
    
    long long g(int n){
    	
    	if(n==1) return 2; 
    	long long sum=0;
    	for(int i=2;i<n;i++){
    		sum=(fa(i,n)+sum)%M;
    	}
    	sum=(sum+4*fa(n))%M;
    	return sum;
    }
    
    int main(){
    	for(int i=1;i<130;i++){
    		int t=g(i);
    		printf("%d:%d
    ",i,t);
    	}
     } 
    优化(缓存):
    #include<cstdio>
    #define M 1000000007
    
    long long fa[1000]={0};
    long long fb[1000]={0};
    
    int f(){
    	fb[1]=1;
    	fb[2]=2;
    	fa[1]=1;
    	fa[2]=6;
    	for(int i=3;i<1000;i++){
    		fb[i]=fb[i-1]*2%M;
    		fa[i]=(fb[i]+fa[i-1]*2+fa[i-2]*4)%M;
    	}
    }
    
    long long g1(int n){
    	
    	if(n==1) return 2; 
    	long long sum=0;
    	for(int i=2;i<n;i++){
    		sum=((fb[i]*fa[n-i]*2%M+fb[n-i+1]*fa[i-1]*2%M)*2%M+sum)%M;
    	}
    	sum=(sum+4*fa[n])%M;
    	return sum;
    }
    
    int main(){
    	f();
    	for(int i=1;i<130;i++){
    		int t=g1(i);
    		printf("%d:%d
    ",i,t);
    	}
     } 
    --------------------------------------

    [6.6 作业]

    环形涂色

    如图,组成环形的格子需要涂3种颜色。
    它们的编号分别是1~14
    相邻的格子不能用相同的颜色。
    涂色方案的数目是:24576

    当格子数目为50的时候,求涂色方案总数。

    思路:
    假设现在考虑最后一个格子填入什么颜色,如果它的前一个格子的颜色和第一个格子的颜色不一样,那么它有两种填法,此时,再看它前面的前面的格子如何填,因为这个格子的后面格子颜色和第一个格子颜色相同,所以相当于之前情况的一个缩小版,有f(n-2)*2种,
    再考虑最后一个格子的前一个格子的颜色和第一个格子的颜色一样,那么它有一种填法,而现在再来考虑这个格子之前应该如何涂颜色,也相当于之前情况的缩小版,于是有f(n-1)*1种。

    代码:
    #include<cstdio>
    #define M 1000000007
    
    long long g(int n){
    	if(n==1) return 3;
    	if(n==2) return 6;
    	
    	return g(n-1)+2*g(n-2);	
    }
    
    int main(){
    	long long a[1000];
    	a[1]=3;
    	a[2]=6;
    	for(int i=3;i<130;i++){
    		a[i]=a[i-1]+2*a[i-2]%M;
    	}
    	
    	for(int i=1;i<130;i++){
    		//long long t=g(i);
    		long long t=a[i];
    		printf("%d:%lld
    ",i,t);
    	}
    }

  • 相关阅读:
    Python Requests-学习笔记(7)-Cookies
    Python Requests-学习笔记(6)-响应头
    Python Requests-学习笔记(5)-响应状态码
    Python Requests-学习笔记(4)-定制请求头和POST
    Python Requests-学习笔记(3)-处理json
    Python Requests-学习笔记(2)
    Python Request-学习笔记(1)
    编程就编程,我不参与政治
    非常漂亮的HTML5音乐播放器
    Dropzone.js实现文件拖拽上传
  • 原文地址:https://www.cnblogs.com/sctb/p/11919659.html
Copyright © 2020-2023  润新知