今天是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;
}
}
}
}
}
}
所以说,只是吓唬人而已…