13周算法

十三周算法训练

//1、Fibonacci数列(至少写出3种算法)

//2、π值求法(至少写出2种算法)

3、循环赛日程表(至少写出3种算法)

//4、0-1背包问题(至少写出3种算法)

//5、最大子段和问题(至少写出3种算法)

//6、判断一个字符串是不是IP地址

要求:1写出算法思想2编程语言为C语言2时间复杂度和空间复杂度4比较各个算法,找出最优算法和算法优化的思路。

(注:从本周开始引入各种算法思想如:分治递归、动态规划、贪心、回溯、分支限界等。)

一、Fibonacci数列

问题描述

1202年,意大利数学家 Fibonacci出版了《算盘全书》。他在书中提出了一个关于兔子繁殖的问题:如果一对兔子(一雄一雌)每月能生一对小兔子,而每对小兔从出生后的第三个月开始,每个月又能生一对小兔,假定在不发生死亡的情況下,由一对出生的小兔开始,问一年后会有多少对兔子?

二、π值求法
问题描述
π是一个在数学及物理学领域普遍存在的数学常数。大写Ⅱ,小写π。π表示数学圆周率,它定义为平面上圆的周长与直径之比,也等于圆的面积与半径平方的比值。
中国数学家刘徽在注释《九章算术》(263年)时用圆的内接正多边形求得π的近似值,也得出精确到两位小数的π值,他的方法被后人称为割圆术。
电子计算机的出现使π值的计算有了突飞猛进的发展。1949年美国马里兰州阿伯丁的军队弹道研究实验室首次用计算机(ENIAC)计算π值,一下子就算到2037位小数突破了小数点后千位数字。1989年美国哥伦比亚大学研究人员用克雷-2型和 ibm-ve 型巨型电子计算机计算出π值小数点后4.8亿位数,后又继续算到小数点后10.1亿位数,创下新的纪录。至今,最新纪录是小数点后25769亿位数。

三、循环赛日程表

问题描述

所谓循环赛,是指每个队都能和其他队比赛一次,最后按成绩计算名次。这种竞赛方法比较合理、客观和公平,有利于各队相互学习和交流经验。假设有n位选手参加循环赛,循环赛共进行n-1天,每位选手要与其他n-1位选手比赛一场,且每位选手每天必须比赛一场,不能轮空,要求为比赛安排日程。

四、背包问题

问题描述

背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。相似问题经常出现在商业、组合数学,计算复杂性理论、密码学和应用数学等领域中。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?它是在1978年由Merkel和Hellman提出的。

它的主要思路是假定某人拥有大量物品,重量各不同。此人通过秘密地选择一部分物品并将它们放到背包中来加密消息。背包中的物品总重量是公开的,所有可能的物品也是公开的,但背包中的物品是保密的。附加一定的限制条件,给出重量,而要列出可能的物品,在计算上是不可实现的。背包问题是熟知的不可计算问题,背包体制以其加密解密速度快而引人注目。

设有一个背包可以放入的物品重量为s,现有n件物品,重量分别是w1,w2,w3,…,wn。问能否从这n件物品中选择若干件放入背包中,使得放入的重量之和正好为s。如果有满足条件的选择,则此背包有解,否则此背包问题无解。

五、最大子段和问题

问题描述

最大子段和是一个常见而且经典的模型,又是一类基本的DP模型,最大子段问题是对于给定序列[x1,x2,x3,…]寻找它的某个连续子段,使得其和最大。如:{-1,5,-2 1,-7,-4,2,3,-1,2}的最大子段是{2,3,-1,2},其和为6。这个问题可以通过枚举分治、动态规划等几种方法来求解。

六、判断一个字符串是不是IP地址

注:十四周先分组讲述分治递归、动态规划、贪心这三个算法思想。


// 一   数列

//1
#include<stdio.h>   //F[n]=F[n-1]+F[n-2](n>=2,F[0]=0,F[1]=1 n=2 1) 
long long a[10000];
long long  f(int x)
{	if(x==0) return a[x]=0;
	if(x==1||x==2) return a[x]=1;
	else if (a[x]>-1) return a[x];
	else return a[x]=f(x-1)+f(x-2);
}
int main()
{
	int n;,
	int i;
	while(1)
	{
		for(i=0;i<10000;i++)   //初始化  -1标识 
		{
			a[i]=-1;
		}
		printf("in put n:");
		scanf("%d",&n);
		printf("\n%lld\n",f(n));	
	}
	return 0;
} 
//o(2^n)
//2    

#include<stdio.h>
long long a[10000];
long long f(int x)
{
	if(x==0)
		return 0;
	if(x==1||x==2)
		return 1;
	else 
		return f(x-1)+f(x-2);	
} 

int main()
{	
	int n,i;
	while(1)
	{		
		printf("in put n:");
		scanf("%d",&n);
		printf("\n%lld\n",f(n));
	}
	return 0;	
}
//o(2^n-1)
//3

#include<stdio.h>
int main()
{	
	long long number,t1,t2;
	int n,i;
	while(1)
	{		
		printf("in put n:");
		scanf("%d",&n);
		if(n==1)
		{
			printf("1\n");
		}
		else if(n==2)
		{
			printf("1\n");
						
		}
		else if(n>2)
		{	
			t1=1;t2=1;
			for(i=0;i<n-2;i++)
			{
				number=t1+t2;
				t2=t1;
				t1=number;					
			}
			printf("\n%lld\n",number);
		}
		else
			printf("error!");		
	}
	return 0;	
}

//o(n)
//=====0 1 背包 ====================================================================


//1  动态

#include<stdio.h>
int V[1000][1000];  
int c,n,w[1000],v[1000];// x选取标识 c容量   n物品个数   w物品重量   v价值 
int max(int a,int b)  
{  
   if(a>=b)  
       return a;  
   else return b;  
}  
int main()
{

	int i,j,s;   //s最大价值 
	printf("输入 容量:");
	scanf("%d",&c);
	printf("输入 个数:");
	scanf("%d",&n);
	printf("输入物品重量:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&w[i]);
	} 
	printf("输入物品价值:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&v[i]);
	}
	for(i=1;i<=n;i++)      //  列 控制列数
	{
		for(j=1;j<=c;j++)   //行  控制行数
		{
			if(j<w[i-1])
			{
				V[i][j]=V[i-1][j];    //  V  用来记录最优价值
				
			}
			else
			{
				V[i][j]=max(V[i-1][j],V[i-1][j-w[i-1]]+v[i-1]);		//状态转移方程   判断这个物品放还是不放	
			}
		}
	}
	
	j=c;  
            for(i=n;i>=1;i--)  
            {  
            if(V[i][j]>V[i-1][j])  
                {  
                    x[i]=1;  
                    j=j-w[i-1];  
                }  
            else  
                x[i]=0;  
            }  
            printf("选中的物品是:\n");  
            for(i=1;i<=n;i++)  
            printf("%d ",x[i]);  
            printf("\n");  
		printf("%d\n",V[n][c]);
	
	
} 

//o(n^2)
//2   贪心算法
#include<stdio.h>
typedef struct aa
{
	double x;       //性价比 
	int z;			//记录位置 
	int w;			//重量 
	int v;          // 价值 
}aa;
int main()
{
	aa y[1000],temp;
	int flag[1000],cc,vv;
	int i,j,c,n;   
	printf("输入 容量:");
	scanf("%d",&c);	
	printf("输入 个数:");
	scanf("%d",&n);
	printf("输入物品重量:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&y[i].w);
	} 	
	printf("输入物品价值:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&y[i].v);
	}	
	for(i=0;i<n;i++)   //计算性价比 
	{
		y[i].x=(y[i].v*1.0)/(y[i].w*1.0);
		y[i].z=i;
	}
	for(i=0;i<n-1;i++)   //冒泡 小到大   n个数进行n-1次排序   控制次数 
	{
		for(j=0;j<n-1-i;j++)   //前后冒泡开始比较   控制位次  n-1-i之后的已经排好顺序 
		{
			if(y[j].x>y[j+1].x)
			{
				temp=y[j];
				y[j]=y[j+1];
				y[j+1]=temp;
			}
		}
			
	}
	cc=0;
	vv=0;
	for(i=0;i<n;i++)
	{
		flag[i]=-1;
	}
	for(i=n-1;i>=0;i--)     //从上倒下 依次放入
	{
		if(y[i].w>c)    // 判断能否装下  能装就装 否者跳过  
		{
			continue;
		}
		if((cc+y[i].w)<c)
		{
			cc=cc+y[i].w;
			flag[i]=y[i].z;
			vv=y[i].v+vv;
		}
		else
			break;
	}
	printf("最大价值:%d \n",vv);
	for(i=0;i<n;i++)
	{
		if(flag[i]!=-1)
		{
			printf("选取的位置:%d ",flag[i]+1);
		}
	}
	printf("\n");
	return 0;
}
//o(n^2)

//3    暴力大法

// 把n 换成000000 到 11111111  暴力穷举所有可能
#include<stdio.h>
int cheng(int n)
{
	int i,j=1;
	for(i=0;i<n;i++)
	{
		j=j*2;
	}
	return j;
}
int main()
{
	int n,c,w[1000],v[1000];
	int i,j,z,ww,vv,max,rember;
	printf("输入 容量:");
	scanf("%d",&c);
	printf("输入 个数:");
	scanf("%d",&n);
	printf("输入物品重量:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&w[i]);
	} 
	printf("输入物品价值:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&v[i]);
	}
	max=0;
	for(i=0;i<cheng(n);i++)
	{
		z=i; 
		ww=0;
		vv=0;
		for(j=0;j<n;j++)    //2进制转换  先%  再/   结果倒排为2进制数 
		{
			if(z%2==1)
			{
				ww=ww+w[j];
				vv=vv+v[j];
			}
			z=z/2;
		}
		
		if((ww<=c)&&(vv>max))
		{
			max=vv;
			rember=i;
		}
		
	}
	printf("选取位置:");
	for(i=0;i<n;i++)
	{
		if(rember%2==1)
		{
			printf("%d ",i+1);
		}
		rember=rember/2;
	}
	printf("最大价值:%d\n",max);	
	return 0;
} 

//o(2^n*n)


//===π=============================================================================

//1

#include <stdio.h>//  π/4   =1-1/3+1/5-1/7+1/9....... 
#include <stdlib.h>
#include <math.h>
int main(){
    float s=1;
    double pi=0;
    float i=1.0;
    float n=1.0;
    while(fabs(i)>=1e-7){
        pi+=i;
        n=n+2;
        s=-s; 
        i=s/n;
    }
    pi=4*pi;
    printf("pi的值为:%.10f\n",pi);
    
    return 0;
}



//2

#include <stdio.h>  //pai/2=   2/1*2/3*4/3*4/5*6/5*6/7 
#include <math.h>    //分子 第n个时 n为偶数 =n   n为奇数 =n+1 
int main(){          // 分母 第n个时 n为偶数 =n+1 n为奇数=n 
    double pi=1.0;
    float n=1.0;  // 
    int j;
    for(j=1;j<=10000000;j++)
	{
        if(j%2==0)
		{
            pi=pi*(n/(n+1));
        }else
		{
            pi=pi*((n+1)/n);
        }
        n++;
    }
    pi=2*pi;
    printf("pi的值为:%.6lf\n",pi);

    return 0;
}


//=====子段=====================================================================
//(-2,11,-4,13,-5,2)的最大子段和为20,所求子区间为[2,4].
 
//暴力大法 
#include<stdio.h>
int main()
{
	int start=0,end=0,max;
	int i,j,n,sum=0;
	int num[1000];
	printf("输入有多少个数值:");
	scanf("%d",&n);
	printf("输入数值:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&num[i]);
	}
	max=num[0];
	for(i=0;i<n;i++)   //控制起始位置 
	{
		sum=0;
		for(j=i;j<n;j++)  //遍历结束位置 
		{	
			sum=sum+num[j];
		//	printf("%d   ",sum);	
			if(sum>max)
			{
				start=i+1;    //记录位置 
				end=j+1;
				max=sum;
			}			
		}		
	}
	printf("最大和为:%d \n区间为:%d--%d",max,start,end);	
	return 0;
}
o(n^2)

//  分治

#include<stdio.h>
int max(int i, int j, int k)    //求3者最大值   依此比较  i,j,k 
{  
    if (i>=j && i>=k)  
        return i;  
    return max(j, k, i);  
}   
int max2(int a[], int r, int l)  
{   
    int lmax,lsum,rmax,rsum,m,i;
    if (r < l) 
	{
		return 0; 
	} 
    if (r == l) 
	{
		return a[l];  
	}
    m = (r + l) / 2;     //计算 中间位置 
    lmax=a[m], lsum=0;  
    for (i=m; i>=l; i--)    //计算   左侧  从右边开始连续的最大值 
	{  
        lsum =lsum+a[i];  
        if (lsum > lmax) 
		{
			lmax = lsum; 
		}             
    }      
    rmax=a[m+1], rsum = 0;   //计算   右侧的  从左边开始的连续最大值 
    for (i=m+1; i<=r; i++) 
	{   
        rsum=rsum+a[i];  
        if (rsum > rmax) 	
		{
			rmax = rsum;  
		}      
    }  
    return max(lmax+rmax, max2(a, l, r), max2(a, l+1, r)); //返回三者最大值  
}  
int main()
{
	int i,n;
	int num[1000];
	printf("输入有多少个数值:");
	scanf("%d",&n);
	printf("输入数值:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&num[i]);
	}
	printf("%d",max2(num,n-1,0));  
	return 0;	
}

//o(N*lg^N)




//3 递推求和


#include<stdio.h>
int max3(int *a, int n)  
{  
    int max, flag,i;  
    max = flag = a[0];       //max记录最大值,  flag记录相加大于0的数值和 
    for (i=1;i<n;i++)   //因为对 max flag 用a[0]进行了初始化  则i从1开始 进行n-1次 遍历 
	{  
        if (flag <= 0)    //先对flag进行处理,只保存对相加有利的和  也就是>1的 
        {
        	flag = a[i];  //否则  舍弃  从当前位开始重新相加 
        }           
        else  
        {
        	flag=flag+a[i]; 
        }     
		
		  
        if (flag > max)  //max记录flag出现过的最大值 
		{  
            max=flag;  
        }  
    }  
    return max;  
}  
int main()
{
	int i,n;
	int num[1000];
	printf("输入有多少个数值:");
	scanf("%d",&n);
	printf("输入数值:");
	for(i=0;i<n;i++)
	{
		scanf("%d",&num[i]);
	}
	printf("%d",max3(num,n));  
	return 0;	
}

//o(n)


///  =====================ip地址========================================

#include<stdio.h>   //区分 . 判断10进制 还是32进制   
#include<string.h>
int judge1(char *ip)   //先区分  01  还是普通  
{
	int i,count;
	for(i=0;i<33;i++)
	{
		if(ip[i]=='.')
		{
			return 1;	
		}
	}
	return 0;
}
int judge2(char *ip,int n)   //普通 
{
	int i,count=0,number=0,flag=0,j=0;
	char a[3],b[3],c[3],d[3];
	for(i=0;i<n;i++)
	{
		if(((ip[i]<'0')||(ip[i]>'9'))&&(ip[i]!='.'))  //判断是否是数字 
		{
			return 0;
		}
		if(ip[i]=='.')     //遇到 .  后  判断是否大于 255 
		{
			count++;
			if(number>=0&&number<=255)
			{
				number=0;
			}	
			else
				return 3;	
		}
		if(ip[i]!='.')
		{
				number=number*10+(ip[i]-'0');   //转换成数值 
		}	
	}	
	if(count!=3)     //判断  .  的个数 
	{
		return 4;
	}
	
	for(i=0;i<3;i++)
	{
		a[i]=b[i]=c[i]=d[i]='!';
	}
	flag=0;
	j=0;
	for(i=0;i<n;i++)
	{	
		if(ip[i]=='.')
		{
			i++;
			break;
		}	
			a[j]=ip[i];	
			j++;			
	}
	j=0;
	for(i;i<n;i++)
	{
		if(ip[i]=='.')
		{
			i++;
			break;
		}	
		b[j]=ip[i];
		j++;
	}
	j=0;
	for(i;i<n;i++)
	{
		if(ip[i]=='.')
		{
			i++;
			break;
		}	
		c[j]=ip[i];
		j++;
	}
	j=0;
	for(i;i<n;i++)
	{
		if(ip[i]=='.')
		{
			i++;
			break;
		}	
		d[j]=ip[i];
		j++;
	}

		for(i=0;i<1;i++)     //除去 012  的可能 
		{
		if(a[i]=='0'&&a[i+1]>'0')
		{
			return 9;
		}
		if(b[i]=='0'&&b[i+1]>'0')
		{
			return 9;
		}
		if(c[i]=='0'&&c[i+1]>'0')
		{
			return 9;
		}
		if(d[i]=='0'&&d[i+1]>'0')
		{
			return 9;
		}
	}
	
/*	for(i=0;i<40;i++)
	{
		a[i]=-1;		
	}
	for(i=1;i<n+1;i++)
	{
		a[i]=ip[i-1];
	}
	for(i=0;i<n+2;i++)
	{
		if((a[i]==-1)&&a[i+1])
	}*/
	return 1;
	
}
int judge3(char *ip)   //01 
{
	
	
}
int main()
{
	char ip[33];
	int i,j,pan,pan1,len=0;
	printf("输入 IP 地址:");
	gets(ip);	
	len=strlen(ip);
	pan=judge1(ip);
		printf("%d ",pan);
	if(pan==1)//普通 
	{
		pan1=judge2(ip,len);
	}
	if(pan==0)//01 
	{
		pan1=judge3(ip);		
	}
	printf("%d ",pan1);	
	if(pan1==1)
	{
		printf("ok");
	}
	else
		printf("no!");
	
	return 0;
} 



///



#include<stdio.h>
int a[1000][1000];

int put_out(int n,int k)   //n个选手   k是阶次 
{
	int i,j,l,m,p;
	for(i=1;i<=n;i++)
	{
		a[1][i]=i;
	}
	
/*	for(i=0;i<n;i++)
	{
		printf("%d ",a[0][i]);
	}
*/	
	m=1;
	for(l=0;l<k;l++)   //控制填充次数 
	{
		n=n/2;
		for(p=1;p<=n;p++) //左右填充次数  n次最小块的调换 
		{
			                          //控制的对角线调换 
			for(i=m+1;i<=2*m;i++)     //控制最小块行 
			{
				for(j=m+1;j<=2*m;j++)  //最小块的列 
				{
					a[i][j+(p-1)*m*2]=a[i-m][j+(p-1)*m*2-m];
					a[i][j+(p-1)*m*2-m]=a[i-m][j+(p-1)*m*2];
					
				}
			}
		}
		m=m*2;
	}
	
	return 1;
}
int main()
{	
	int k,i,n=1,j,count=1;
	printf("输入2^k的k值:");
	scanf("%d",&k);
	for(i=0;i<k;i++)
	{
		n=2*n;
	}
//	printf("%d\n",n);
	put_out(n,k);
	for(i=1;i<=n;i++)
	{
		printf("%d号 :",count++);
		for(j=2;j<=n;j++)
		{
			
			printf("%d  ",a[i][j]);
		}
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值