番外——练过的题目/算法总结(持续更新)

今天是2019.4.2
打算以后吧练过的题都放在这里,供整理用,毕竟也是加了个计算机协会的东西,可能会教一些有意思的东西吧(我们目前还没开数据结构这门课,c语言刚开)
 
  
   
好了那就开始吧
1.现在有100元钞票,要换成等价的10,5,2,1元的钞票,要求每次换成40张且每种至少一张,问可能性

其实第一次看这道题,我是不会的…太菜了,蒟蒻,后面也是问了下同学,同学说,要用遍历(内心:啥玩意儿?!)后面给了我一串代码,感觉,嗯…好有用啊,感觉以后碰到类似的题都不会没思路了。
以下附上代码

#include<stdio.h>
int main (void)
{
	int sum,i;
	for(int a = 1;a<10;a++)
	{
		for(int b = 1;b<20;b++)
		{
			for(int c = 1;<40;c++)
			{
				for(int d = 1;d<40;d++)
				{
					sum = a*10+b*5+c*2+d;
					if(sum==100&&a+b+c+d==40)
					{
						i++;
					}
				}
			}
		}
	}

	printf("%d",i);
	return 0;
}

以上便是我同学的,我看了后,我的想法是,要不我直接把一张10元一张5元一张2元一张1元的钱从100中去掉,那不就不用考虑张数问题了嘛,这样做会不会简单点呢?(并不)
以下是我的代码

#include<stdio.h>
int main (void)
{
	int sum,i;
	for(int a = 0;a<=6;a++)
	{
		for(int b = 0;b<=16;b++)
		{
			for(int c = 0;c<=36;c++)
			{
				for(int d = 0;d<=36;d++)
				{
					sum = a*10+b*5+c*2+d;
					if(sum==82&&a+b+c+d==36)
					{
						i++;
					}
				}
			}
		}
	}

	printf("%d",i);
	return 0;
}在这里插入代码片(插你个头)

嘛,结果到都是一样的。
总之就是遍历,我,学会了!

2.输出图形
a
a b
a b c

一直到z

(长的像个三角形,尖尖在中间的那种,不是这样的!)

直接给代码吧,因为我也不知道怎么讲23333

#include <stdio.h>
#include<Windows.h>
int main (void)
{
	



	int n = 24;
	int x;
	int y;
	int z;
	for(int z = 65;z<91;z++)
	{
		for(int x = 0;x<=n;x++)
		{
			printf(" ");
		}
		for(int y = 65;y<=z;y++)
		{
			printf("%c ",y);
		}
		for(int x = 0;x<=n;x++)
		{
			printf(" ");
		}
		putchar('\n');
		n--;
	}
	

	system("pause");

	return 0;
		
} 

3.输入一个以’’.’'结尾的字符串,统计字母,数字数量
好做,但是呢,看怎么做,我想到的是用那个强制转换,到时候判断ASCII码,但有些编译器不能用(例蓝桥杯专用的那个…)所以呢就int ch;然后判断吧;
以下是代码

#include <stdio.h>
int main (void)
{
	
	int n;
	int a = 0;
	int b = 0;
	while((n = getchar())!='.')
	{
		if((n>='A'&&n<='Z')||(n>='a'&&n<='z'))
		{
			a++;
		}
		if(n>='0'&&n<='9')
		{
			b++;
		} 
	} 
		
	printf("字母%d  数字%d",a,b);
	
	return 0; 
} 

当然在c语言网上面还有强化版,像什么统计字母,数字,空格,其他字符等等…
以上是4.1(周一)的计协题目(我偷来的,我在周二上课哈哈),第二题不会外,剩下还好。
 
  
________________________________________________________________________________   
    
    
以下是星期二,4.2的题目,难度比昨天的简单不少(莫不成是因为昨天是培优班么…)
1.输出1000以内的素数
怎么解呢?我想素数都会求吧,那么这次呢,我让在求素数的过程中,如果一个数在取余的时候==0,那么这个数肯定不是素数了,那我就让n = 1,循环结束后判断n是否等于1,若是,则不输出,若不是,则输出;
代码在下

#include <stdio.h>
#include<windows.h>
//1.1000以内素数
//2.九九乘法表
int main (void)
{
	int s;
	for(int i = 2;i<=1000;i++){
		s = 0;
		for(int m = 2;m<i;m++){
			if(i%m==0){
				s = 1;
			}
		}
		if(s!=1){
			printf("%d ",i);
		}
	}
	
	system("pause");
	return 0;
	
} 

2.乘法表
直接给代码吧,简单题

#include <stdio.h>
#include<windows.h>
//1.1000以内素数
//2.九九乘法表
int main (void)
{

	for(int i = 1;i<=9;i++){
		for(int n = 1;n<=i;n++){
			printf("%d * %d = %d   ",i,n,i*n);
		}
		putchar('\n');

	system("pause");
	return 0;
	
} 

以上是协会练的题
 
  
   
________________________________________________________________________________    
     
     
4.3
以下部分题目源自bilibili ACM专题讲解:基础算法
**1.枚举法 **
在这里插入图片描述
(和那个100元分了有异曲同工之处啊,看来这就是枚举啊…)
代码如下

在这里插入图片描述
(不是我不想写,我是刚才不小心关了,然后写的东西都没了,气死(╬◣д◢))

当然这个枚举太慢了,要运行100100100次,我们要做的是优化
 
  在这里插入图片描述
代码如下

#include <stdio.h>
#include<windows.h>
int main (void)
{
	int a,b,c;
	for(a = 0;a<=20;a++){
		b = 100-7*a;
		if(b%4==0&&b>=0){
			b /=4;
			c = 100-a-b;
			if(c%3 ==0&&3*b+5*a+c/3==100){
				printf("母鸡%d 公鸡%d 小鸡%d\n",a,b,c);
			}
		}
	}

	system("pause");
	return 0;
	
} 

太厉害了…
 
  
   
    
     
      
      
二.递推
递推有顺推和逆推
顺推:斐波那契
逆推:存款,年利率0.03,求n年连本带息取出m元,要一开始存多少钱

代码的话…学长说太简单了不讲了…
 
  
   
    
    
三.贪心
在这里插入图片描述
在这里插入图片描述
但是这讲的也太恐怖了吧,随便说说就没了!看来我还是先去看排序算法吧…

所以说我又回来了,嗯,学了一下冒泡算法,以下附上代码片

#include <stdio.h>
#include<windows.h>
int main (void)
{
	int temp;
	int N;
	N = 6;
	int ch[6] = {1,5,2,47,45,9};

	for(int i = 0;i<N-1;i++){
		for(int j = 0;j<N-i-1;j++){
			if(ch[j]>ch[j+1]){
				temp = ch[j];
				ch[j] = ch[j+1];
				ch[j+1] = temp;
			}
		}
	}

	for(int i = 0;i<=N-1;i++){
		printf("%d ",ch[i]);
	}



	system("pause");
	return 0;
	
} 

具体原理我就不讲了,毕竟我主要是积累一下,何况自己学的也不是很好…

呜呜呜,我刚看了我同学就和我说,c++可以直接排序,用sort()…嘛,多学点总没错,不管了。
 
  
   
    
     
这里附上一道今天下午做的一道题
在这里插入图片描述

哇,感觉有点难,后面还是很费劲的写出来了
下面是书上的代码

#include<cstdio>
#include<algorithm>
using namespace std;


int i=0;//备用 
int A[20005];int B[20005];

int main(){
	int n,m;
while(scanf("%d%d",&n,&m)==2&&n&&m){

	for(i=0;i<n;i++)//不为0,继续,给A[] B[]赋值 
		scanf("%d",&A[i]);
	for(i=0;i<m;i++)
		scanf("%d",&B[i]);
			sort(A,A+n);//排序 
			sort(B,B+m);
		int N=0;//第几个头 
		int sum=0;//佣金 
		for(i=0;i<m;i++)/*从弱到强遍历骑士 */
			{
				if(B[i]>=A[N])//第i+1个骑士比第N+1个头强 
					sum+=B[i];//佣金增加 
					N++;//下一个龙头
				if(N==n)//是否砍完头了 
					break;//另外,如果佣兵不够也停止循环 
		
		}
		if(N<n)printf("Loowater is doomed!\n");//没砍完 
		else printf("%d\n",sum);	//砍完了,输出佣金 
}
	return 0;
}//感谢某赵姓黑贞控提供的代码与注释

在这里插入图片描述

而这是我的

#include <cstdio>
#include<algorithm>
#include<windows.h>
#include<iostream>
#define N 20005
 using namespace std; 
 int n[N];//头的数组
 int m[N]; //骑士的数组
 int x[N];//最后判定结果用到的数组
 int temp = 0;
int main (void)
{
	int n1,m1;
	int a,b;
	int j = 0,sum = 0;
	 int q;
	int w = 0;
	
	
	
	do{//do循环,判断是否输入的n,m==0,若等于0则跳出循环
	
		scanf("%d%d",&n1,&m1);//读入n,m,我这写的n1,m1
	
		for(int x1 = 0;x1<N;x1++){/*让头的数组(n的数组)与*/
			n[x1] = 100000;        /*和骑士的数组初值全部设为一个很大的数字*/  
		}								/*便于后面排序(相当于是赌输入的数据比这个数字小,要是大了我就赌输了)*/
		for(int x1 = 0;x1<N;x1++){
			m[x1] = 100000;
		} 
		
	



		for(int i = 0;i<n1;i++){/*把读入头的数据放入n*/
			scanf("%d",&a);
			n[i] = a;
		}
		for(int j = 0;j<m1;j++){//把骑士的数据放入m
			scanf("%d",&b);
			m[j] = b;
		}
	
		
		sort(n,n+N);//排序
		sort(m,m+N); //排序,低的在前面,举个栗子1,4,6,7,100000,100000...
		
		
		for(int i = 0;;i++){//这个循环会一直运行下去,因为我没设跳出条件,所以要想跳出得用到break
		
			if(m[i]>=n[j]&&m[i]!=100000){//i==0,j也==0,如果骑士的力量大于龙头的力量,则
				j++;					//让j++,代表第一个龙头没了,该第二个了,sum用来算钱
				sum+=m[i];				//!=100000是因为那个数是我设的不是用户输入的,
			}							//若龙头值==100000,代表用户输入的龙头数据已经全部跳过了
			if(m[i]==100000||n[i]==100000){//因为控制勇士力量的数组变量是i,i在for循环里设置了i++
				temp = i;				//所以不用管它
				break;					//等于是判定当最后龙头和勇士一样大,也算赢
			}							//第二个循环,判断如果有一方的数据==100000(代表用户输入的数
										//据已经输完,则跳出循环,并记住当前i的值,用temp标记
		}
	

		if((m[temp]==100000)){
			
			q = 0;						//判断如果是勇士数据先到的100000,换言之,勇士的数据先跳完,
				x[w] = q;				//代表,勇士死光了,则输,用q==0记录
				w++;					//x数组表示记录胜负情况,(最初w=0,记录一次后w++)
		}
		else if(n[temp]==100000||(m[temp]==100000&&n[temp]==100000)){
				q = 1;						//同理,若龙先到0或者两者都到0,则赢。
				x[w] = q;
				w++;
		}
		
	}while((n1!=m1)&&n1!=0&&m1!=0);	
	

	for(int i = 0;i<w-1;i++){//判断w数组的值,若==0则输出输,若==1则输出sum值(金钱)
	

		if(x[i]==0){
			printf("输了\n");
		}
		else if(x[i]==1){
			printf("%d\n",sum);
			
		}
	}	

	system("pause");
	return 0;
	
} 

看看就知道差别太大了…需要学习的东西还有很多… 
 
  
   
    
    
给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个。
输入格式
第一行包含一个整数n。
第二行包含n个非负整数,为给定的数列,数列中的每个数都不大于10000。
第三行包含一个整数a,为待查找的数。
输出格式
如果a在数列中出现了,输出它第一次出现的位置(位置从1开始编号),否则输出-1。
样例输入
6
1 9 4 8 3 9
9
样例输出
2

以下是我的答案

#define N 100000
int main (void)
{
	int a;
	int b;
	
	int ch[N];
	scanf("%d",&a);
	for(int i = 0;i<a;i++){
		scanf("%d",&ch[i]);
	}

	scanf("%d",&b);

	for(int i = 0;i<a-1;i++){
		if(b==ch[i]){
			printf("%d",i+1);
			system("pause");
			return 0;
		}
	}
	printf("-1");
	
	system("pause");
	return 0;
}

简单题,不值一提
 
  
   
    
     
     
附上计协的题
**题目描述
将十进制数n转换成m进制数 m<=16
n<=100
输入描述:共1行,n和m
输出描述:共一个数 表示n的m进制
样例输入
样例1:10 2
样例2:100 15
样例输出
样例1:1010
样例2:6A
**
10进制转任意进制…难点在于A,B,C…的输出,我想的办法是再创一个数组,储存’A’,‘B’…这些东西,然后判断,如果=10.则,输出A,如果=11,则输出B
以下是代码片

int main (void)
{


	int a,b;
	int c = 0;
	int ch[N];
	int temp;
	char ch1[6] = {'A','B','C','D','E','F'};
	scanf("%d%d",&a,&b);

	while(a/b>=b){
		ch[c] = a%b;
		a = a/b;
		c++;
	}
	if(a/b<b){
		
		ch[c] = a%b;
		temp = c+1;
		ch[temp] = a/b;
	}

	

	for(int i = temp;i>=0;i--){
		
		switch (ch[i]){
		
		case 10:
		printf("%c",ch1[0]);
		break;

		case 11:
		printf("%c",ch1[1]);
		break;

		case 12:
		printf("%c",ch1[2]);
		break;

		case 13:
		printf("%c",ch1[3]);
		break;

		case 14:
		printf("%c",ch1[4]);
		break;

		case 15:
		printf("%c",ch1[5]);
		break;

		default:
			printf("%d",ch[i]);
			break;
		}
		
		
			
	}

	system("pause");
	return 0;


}

用switch来判断情况,因为情况比较多,所以用switch方便些,用if也不是不行。

————————————————————————————————————————————

所以说我还是把那个b站视频看完吧
还是那个贪心
在这里插入图片描述
在这里插入图片描述

现在再看,感觉懂一点意思了,
首先先排序,ans是代价,拿1,2,3,4,5来举栗子
第一个for循环,做的是让前两堆果子合在一起,那么就是1,3,3,4,5,
这时候没用到第二个for循环,然后进行第二次循环
及果实1,3,6,4,5,这时候就要用到第二个for循环了,第二个for循环的作用是交换两个数字的位置,为什么呢?为的就是让每次加数都是最小
举例吧
1,3,3,4,5,在合并成为,1,3,6,4,5;如果不交换位置,则加的数是6,但如果交换的话,那个数就会是1,3,4,6,5,答案是4,
因为求的是最小代价,所以得交换
//弹幕有人说程序错了,我觉得也像,你想
//1,2,3,4,5,1和2在一起是3,3和3在一起是6,接下来应该是4和5在一起才对吧…
那该怎么改呢?
我觉的少一个i++,当然不能直接写i++,得设一个变量x等于上面的i,然后在第二个循环的时候加上x,让x++;

四.递归
斐波那契,不必多说(不仅是我,连ppt上也是,一带而过,我相信他会在后面课程中讲的…)

五.分治
在这里插入图片描述
分治用到了递归的思想…
在这里插入图片描述
代码如下
在这里插入图片描述
哇这个是真的秀啊,

六.构造
在这里插入图片描述
七.模拟
在这里插入图片描述
听起来好简单…

8.排序
在这里插入图片描述
来了来了,重头戏!

…原谅我昨天看完以后没能写博客…太累了脑袋疼

———————————————————————————————————————————
今天是4.5
清明放假,来愉快的做题吧(笑)
关于《算法竞赛入门经典》上的例题,我的想法是,积累为主。自己思考时间不宜过长,浪费时间有点,积累为主,比如下面这道题。
1.开关灯在这里插入图片描述

代码如下

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#define X 1000
using namespace std;
int ch[X];
int main (void)
{
	//string.h里面,记住有个memcpy(b,a,sizeof(a)),作用是把a数组全部复制到B数组,如果是K个元素则是memcpy(b,a,sizeof(int)*k)


	memset(ch,0,sizeof(0));
	int n,k,first = 1;
	scanf("%d%d",&n,&k);
	
	for(int i = 1;i<=k;i++){
		for(int j = 1;j<=n;j++){
			if(j%i==0){
				ch[j]=!ch[j];
			}
		}
	}

	for(int i = 1;i<=n;i++){
		if(ch[i]){
			if(first){
				first = 0;
				printf("%d",i);
				
			}
			else{
				printf(" ");
				printf("%d",i);
			}
		}
	}

	system("pause");

	return 0;
}

整体思路是,先想,你要是都开,我可以设置成都是0.那么要是有人开灯,那么那个数我我取1,这样好了,最后判断哪些是1就行,
书上的代码比较简单,他用到了非0即真,所以呢,if(ch【i】)
代表如果ch【i】不是0,则进行下面的if判断。
关于那个first,第一个数字前是不应该加空格的所以相当于是先输出首位.且不加空格。
 
  
   
   
2,蛇形矩阵
nn的方阵中填入1,2,…,nn,要求是蛇形。例n = 4时
在这里插入图片描述
在这里插入图片描述
以下是代码

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#define X 30
using namespace std;
int ch[X][X];
int main (void)
{
	memset(ch,0,sizeof(0));

	int n,x,y,tot;
	scanf("%d",&n);
	tot = ch[x = 0][y = n-1] = 1;

	while(tot<n*n){
		while(x+1<n&&!ch[x+1][y]) ch[++x][y] = ++tot;
		while(y-1>=0&&!ch[x][y-1]) ch[x][--y] = ++tot;
		while(x-1>=0&&!ch[x-1][y]) ch[--x][y] = ++tot;
		while(y+1<n&&!ch[x][y+1]) ch[x][++y] = ++tot;
	}

	for(int i = 0;i<n;i++){
		for(int j = 0;j<n;j++){
			printf("%3d",ch[i][j]);			
		}
		printf("\n");
	}


	system("pause");

	return 0;
}

思路书上说的很清楚,在这里我也是简单说一下,先考虑怎么走,哪里是头?先定好,然后想,我向下走,1.这个数必须没越界,2这个数一定是0(代表没走过),这么一想,while就得有两个条件牵制怎么走,然后下边有了,进而推出左,上,右…等等
最后用循环输出二位数组
————————————————————————————————————————————
4.6
来愉快的学习数据结构吧
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
学长说:大家上学期都学过c++了,老师也都让写过链表
我:???我还没学完c呢…
在这里插入图片描述
由于学长直接用的是c++上的头文件进行做题,所以我就不附上题目和代码了(因为看不懂)
也总算是知道为什么要学c++了,太方便了!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.23
有的时候也是在想,简单题要不要弄上来呢?

————————————————————————
5.14
不管怎样,看看这题目就感觉充满了决心!
这是今天计协的题目

1.移除重复的数字
给定一个升序排列的数组,去掉重复的数,并输出新的数组的长度。
例如:数组A={1,1,2},你的程序应该输出 2 即新数组的长度,新数组为 {1,2}。
要求:不能新开数组分配额外的空间,即常数空间限制。
输入格式
输入一个整数 n(1≤n≤1000)。
接下来一行 n 个整数Ai(1000≤Ai≤1000),表示数组 A 中的每个元素。
输出格式
输出一个整数,表示新数组长度。
样例输入
5
0 0 1 1 2
样例输出
3

#include<stdio.h>
#include<windows.h>
#define N 1005
/*1.移除重复的数字
给定一个升序排列的数组,去掉重复的数,并输出新的数组的长度。
例如:数组A={1,1,2},你的程序应该输出 2 即新数组的长度,新数组为 {1,2}。
要求:不能新开数组分配额外的空间,即常数空间限制。
输入格式
输入一个整数 n(1≤n≤1000)。
接下来一行 n 个整数Ai(1000≤Ai≤1000),表示数组 A 中的每个元素。
输出格式
输出一个整数,表示新数组长度。
样例输入 
5
0 0 0 0 1 1 2
样例输出 
3*/
int main (void)
{

	int n;
	int ch[N];
	int t;
	int answer;
	scanf("%d",&n);

	for(int i = 0;i<N;i++){
		ch[i] = 1005;
	}

	for(int i = 0;i<n;i++){
		scanf("%d",&ch[i]);
	}

	for(int i = 0;i<n-1;i++){
		while(ch[i]==ch[i+1]){//0 0 0 1 1 2
			t = i;
			for(int j = t;j<n;j++){
				ch[j+1] = ch[j+2];//
			}
			n--;
		}
	}

	for(answer = 0;answer<n;answer++){
		if(ch[answer]==1005){
			break;
		}
	}
	printf("%d\n",answer);


	system("pause");
	return 0;
	
} 

怎么说呢,第一眼看题目还觉得有点意思,做完就发现,啧啧,挺简单的

第二题…真是…
2.四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838

#include<stdio.h>
#include<windows.h>
#define N 1005
/*2.四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入:
5
则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序应该输出:
0 2 2 2
再例如,输入:
773535
则程序应该输出:
1 1 267 838
*/
int main (void)
{
	int s;
	scanf("%d",&s);
	for(int a = 0;a<1000;a++){
		for(int b = 0;b<1000;b++){
			for(int c = 0;c<1000;c++){
				for(int d = 0;d<1000;d++){
					if(a*a+b*b+c*c+d*d==s){
						printf("%d %d %d %d\n",a,b,c,d);
						system("pause");
						return 0;
					}
				}
			}
		}
	}
	
} 

所以说,只是吓唬人而已…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值