深入浅出程序设计竞赛(洛谷基础篇) 第七章 函数与结构体

电子版教材链接
我通过百度网盘分享的文件:深入浅出程序设计…pdf
链接:https://pan.baidu.com/s/1kmF8wZLnK3Zci7s1ffjRzw
提取码:Ra3Q
复制这段内容打开「百度网盘APP即可获取」

例7-1 距离函数
#include <bits/stdc++.h>;
using namespace std;

double sq(double x)
{
	return x*x;
}

double dist(double x1,double y1,double x2,double x3)
{

	return sqrt(sq(x1-x2)+sq(y1-y2));
}

int main()
{
	double x1,y1,x2,y2,x3,y3,ans;
	scanf("%lf%lf%lf%lf%lf%lf".&x1,&y1,&x2,&y2,&x3,&y3);
	ans = dist(x1,y1,x2,y2);
	ans += dist(x1,y1,x3,y3);
	ans += dist(x2,y2,x3,y3);
	printf("%.2f",ans);
	return 0;
}
例7-2 质数筛
#include <bits/stdc++.h>
using namespace std;

bool is_prime(int x)
{
	if(x==0 || x==1 ) return 0;
	for(int i = 2;i*i<=x;i++)
	{
		if(x%i == 0)
		{
			return 0;
		}
		
	}
	return 1;
}


int main()
{
	cin >> n;
	for(int i = 0;i<n;i++)
		cin >> a[i];
	for(int i = 0;i<n;i++)
	{
		if(is_prime(a[i])
			cout << a[i] << " ";
	}
	cout << endl;
	return 0;
}
例7-3 闰年展示
#include <bits/stdc++.h>
using namespace std;

//声明函数
void init();
void doit();
void output();

int x,y,ans[505],cnt;

int main()
{
	init();
	doit();
	output()'
	return 0;
}

void init()
{
	cin >> x >> y;
}

void doit()
{
	for(int i = x;i<=y;i++)
	{
		if(!(i%400) || !(i%4) && i%100)
			ans[cnt++] = i;
	}
}

void output()
{

	cout << cnt << endl;
	for(int i = 0;i<cnt ;i++)
	{
		cout << ams[i] << endl;
	}
	cout << endl;
}

例7-4 歌唱比赛
#include <bits/stdc++.h>
using namepspace std;
iint s[25],n,m,maxsum;

void nihao(int a[],int m)
{
	int maxscore = 0,minscore = 10,sum = 0;
	for(int i = 0;i<m;i++)  // 这里使用的是打擂台的方式,实际上也可以使用排序的方法进行替换
	{
		maxscore = max(a[i],maxscore);
		minscore = min(a[i],minscore);
		sum += a[i];
	}
	maxsum = max(maxsum,sum - maxscore - minscore);  // 减去一个最高分再减去一个最低分,并比较该同学是否得分比上一个同学的高,使用了一个max函数进行约束条件判断
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 0;i<n;i++)
	{
		for(int j = 0;j<m;j++)
		{
			scanf("%d",&s[j]);
		}
		nihao(s,m);
	}
	printf("%.2f",double(maxsum)/(m-2));  // 最后计算一下平均值
	return 0;
}
例7-5 交换两个变量的值
前置知识

如果要函数改变形参(函数括号里的参数)的效果也作用在实参(在主程序中被声明的参数)上,我们需要使用指针传递或者地址传递的方法

这里的int &x 是使用了地址传递的方法,这种传递的方法比值传递方法的优胜之处在于,值传递只是创建了一个副本,并没有真正的影响到外面的实参,而地址传递直接链接了函数内部与实参,所以是的修改了形参等价于修改了实参

#include <bits/stdc++.h>
using namepspace std;

void swap(int &x,int &y)
{
	int t = x;
	x = y;
	y = y;
}

int main()
{
	int a,b;
	cin >> a >> b;
	swap(a,b);
	cout << a << " " << b << endl;
	return 0;
}
例7-6 自动修正加强版

Tips:

Q:上面不是说了要指针传递或者地址传递才能修改实参吗,这里函数中的string s没有使用地址传递或者指针传递啊,为什么也可以实现了修改实参的效果呢?

A: string类型传入函数就自动复制了一份新的字符串,所有的改动都在新的字符串上进行,所以返回的不是原来的那个字符串,应该初始化一个新的变量(s2)来承载s1的副本,如果只是正常的返回起始还是没有起到修改实参的效果,本质上就是修改了原字符串的副本而已

#include <bits/stdc++.h>
using namespace std;

string to_upper(string s)
{
	for(int i = 0;i<s.length();i++)
	{
		if('a'<=s[i] && s[i] <='z')
		{
			s[i] -= 'a' - 'A';
		}
	}
	return s;
}

int main()
{
	string s1,s2;
	getline(cin,s1);
	s2  = to_upper(s1);
	cout << s1 << endl << s2 << endl;
	return 0;
}
例7-7 计算阶乘
#include <bits/stdc++.h>
using namespace std;
// 这里使用了递归的方法来计算阶乘

int fn(int x)
{
	if(x==1) return 1;
	return x* f(x-1);
}

int main()
{
	int n;
	cin >> n;
	cout << f(n) << endl;
	return 0;
}
例7-8 赦免战俘

算法竞赛中的坐标轴:

(0,0) ±-------→ x
|
|

y
i<<n : 表示 i * 2^n;

#include <bits/stdc++.h>
using namespace std;

const int N 1050;

int a[N][N],n;

void cal(int x,int y,int n)
{
	if(n == 0) a[x][y] = 1;
	else
	{
		cal(x +(1 << n-1),y,n-1);  // 右上方矩阵
		cal(x,y+(1<<n-1),n-1); // 左下角矩阵
		cal(x+(1<<n-1),y+(1<<n-1),n-1);  // 右下角矩阵
	}
}

int main()
{
	int n;
	scanf("%d",&n);
	cal(0,0,n);
	for(int i = 0;i< 1<<n;i++)
	{
		for(int j = 0;j< 1<<n;j++)
		{
			printf("%d%c",a[i][j],j == (1<<n) - 1?'\n': ' ');  // 判断是否为该行最后一列。是则换行,否则空格分隔
		}
	}
	
	return 0;
}
例4-9 最厉害的学生
前置知识

结构体 :

// 定义结构体
struct 类名{
	数据类型 成员变量;
} 结构体变量名 ;

// 初始化结构体
strcut 类名 结构体变量名;

#include <bits/stdc++.h>
using namespace std;

struct nihao
{
	string name;
	int chinese,math,english;

} a, ans;  // 直接初始化了对象

int main()
{
	int n;
	cin >> n;
	for(int i = 1;i<=n;i++)
	{
		cin >> a.name >> a.chinese >> a.math >> a.english;
		if(a.chinese + a.math + a.english > ans.chinese + ans.math + ans.english)
			ans = a; // 比较两个结构体的大小,如果这个更大就更新为它
	}	
	cout << ans.chinese << " " << ans.math << " " << ans.english << " "<< endl;
	
	return 0;
}
例7-10 旗鼓相当的对手
#include <bits/stdc++.h>
using namespace std;
  

struct Student
{
	string S_name;
	int chinese,math,English;
};

int main()
{
	Student arr[10000];
	int N;
	cin >> N;
	for(int i = 1;i<=N;i++)
	{
		cin >> arr[i].S_name >> arr[i].chinese >> arr[i].math >> arr[i].English;
	}
	for(int i = 1; i <= N; i++)
	{
		for(int j = i + 1; j <= N; j++)
		{
			if((abs(arr[j].chinese - arr[i].chinese) <= 5)
			&& (abs(arr[j].math - arr[i].math) <= 5)
			&& (abs(arr[j].English - arr[i].English) <= 5)
			&& (abs(arr[j].chinese + arr[j].math + arr[j].English - (arr[i].chinese + arr[i].math + arr[i].English)) <= 10))
			{
				if(arr[i].S_name>arr[j].S_name)//系统会自己判断字典序
					cout<<arr[j].S_name<<" "<<arr[i].S_name<<"\n";
				else cout<<arr[i].S_name<<" "<<arr[j].S_name<<"\n";
			}
		}
	}
	return 0;
}
例7-11 评等级
#include <bits/stdc++.h>
using namespace std;
int N;
  
struct Student
{
	int ID,score,suzhi_score;
}arr[1010];

  
bool is_Excesslent(Student s1)
{
	if((s1.score * 7 + s1.suzhi_score *3) >= 800 && s1.score+s1.suzhi_score > 140 )
	{
		return 1;
	}
	return 0;
}

int main()
{
	cin >> N;
	for(int i = 1;i<=N;i++)
	{
		cin >> arr[i].ID >> arr[i].score >> arr[i].suzhi_score;
	}
	for(int i = 1;i<=N;i++)
	{
		if(is_Excesslent(arr[i]))
		{
			cout << "Excellent" << endl;
		}
		else cout << "Not excellent" << endl;
	}
	
	return 0;
}

习题7-1和习题7-2都是理论判断题,读者可以自行查看

习题7-3 质因数分解
#include <bits/stdc++.h>
using namespace std;

int n;

bool is_prime(int x)
{
	if(x==0 || x==1 ) return 0;
	for(int i = 2;i*i<=x;i++)
	{
		if(x%i == 0)
		{
			return 0;
		}
		
	}
	return 1;
}

int main()
{
	cin >> n;
	for(int i = 1;i<=sqrt(n);i++)
	{
		if(n%i == 0 && is_prime(i))
		{
			int others = n/i; 计算另外一个因子
			if(i!=others && is_prime(others))
			{
				int s = max(i,others);
				cout << s;
				break;
			}
		}
	}
	return 0;
}
习题7-4 哥德巴赫猜想
#include <bits/stdc++.h>
using naemspace std;

bool is_prime(int x)
{
	if(x==0 || x==1 ) return 0;
	for(int i = 2;i*i<=x;i++)
	{
		if(x%i == 0)
		{
			return 0;
		}
		
	}
	return 1;
}

void print(int a)
{
	if(a == 4)
	{
		printf("4=2+2\n");
		return;
	}
	for(int i = 3;i+2<=a;i+=2)
	{
		if(isPrime(i) && 2+i==a)
		{
			printf("%d=2+%d\n",a,i);
			return;
		}
	}

	for(int i = 3;i+3 <=a;i+=2)
	{
		//除了2以外的所有质数都是奇数
		if(isPrime(i) && isPrime(a-i)) // a是偶数
		{
			printf("%d=%d+%d\n",a,min(i,a-i),max(i,a-i)); //保证打印出来的是有序的
			return ;
		}
	}

}

int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 4;i<=n;i+=2)
	{
		printf(i); // 调用函数
	}
	
	return 0;
}
习题7-5 回文质数
#include <iostream>
using namespace std;

//判断是否为质数的函数
bool is_prime(int n) {
    if (n <= 2) return false;
    if (n % 2 == 0) return false;  
    for (int i = 3; i * i <= n; i += 2) {
        if (n % i == 0) return false;
    }
    return true;
}

int main()
{
	int a,b;
	cin >> a >> b;
	if(a<=5 && b>=5) cout << 5 << endl;
	if(a<=7 && b>=7) cout << 7 << endl;
	if(a<=11 && b>=11) cout << 11 << endl;

	for(int d1 = 1;d1<=9;d1++)
	{
		for(int d2 = 0;d2<=9;d2++)
		{
			int num = d1*100 + d2*10 + d1;
			if(num < a) continue;
			if(num > b) return 0;
			if(is_prime(num))
				cout << num << endl;
		}
	}

	for(int d1 = 1;d1<=9;d1++)
	{
		for(int d2 = 0;d2<=9;d2++)
		{
			for(int d3 = 0;d3<=9;d3++)
			{
				int num = d1*10000 + d2 *1000 + d3*100 + d2*10 + d1;
				if(num < a) continue;
				if(num > b) return 0;
				if(is_prime(num))
					cout << num << endl;
			}
		}
	}


	for(int d1 = 1;d1<=9;d1++)
	{
		for(int d2 = 0;d2<=9;d2++)
		{
			for(int d3 = 0;d3<=9;d3++)
			{
				for(int d4 = 0;d4<=9;d4++)
				{
					int num = d1*1000000 + d2 *100000 + d3*10000+ d4*1000 +d3*100 + d2*10 + d1;
					if(num < a) continue;
					if(num > b) return 0;
					if(is_prime(num))
						cout << num << endl;
				}
			}
		}
	}

	return 0;
}

习题7-6 集合求和

模拟来找出数学规律:
这里的元素之和就是原集合中元素之和

1.当集合只有一个元素时,元素之和只会出现一次

2.当集合出现两个元素时,元素之和会出现1+1次(一次是子集只有一个元素,元素之和(两个这样只有一个元素的子集之和)数到一次,一次是子集有两个元素,元素之和又数到一次)

3.当集合出现三个元素时:

子集一个元素:多个这样的子集相加,会让元素之和出现一次

子集两个元素:分为子集A,B,C,有原集合(1,2,3),A(1,2),b(2,3),C(1,3),将ABC进行元素相加,刚好之和是原集合元素之和的两倍

子集三个元素:就是母集本身,元素之和出现了一次

总结规律

1

1 1

1 2 1

1 3 3 1

发现是杨辉三角 每一行之和是 pow(2,i-1) i表示第几行

最后要求的结果就是元素之和乘以杨辉三角之和(其实就是表示元素之和出现了几次)

#include <bits/stdc++.h>
using namespace std;

int main()
{

	long long tmp,num=0,sum=0;
	
	while(cin>>tmp){sum+=tmp;num++;}//读入集合元素个数num和元素和sum
		cout<<(long long)(sum*pow(2,num-1));//必须显式地转换为long long输出
	return 0;
}
习题7-7 猴子吃桃
#include <bits/stdc++.h>
using namespace std;

int remain(int n)
{
	if(n == 1) return 1;
	else return 2*(remain(n-1)+1);

}

int main()
{
	int n; // n表示天数
	cin >> n;
	int a = remain(a);
	cout << a << endl;
	return 0;
}
习题7-8 培训
#include <bits/stdc++.h>
using namespace std;

struct nihao{
	string name;
	int age;
	double score;

}arr[6];

void in(int &n)
{
	cin >> n;
	for(int i = 1;i<=n;i++)
	{
		cin >> arr[i].name >> arr[i].age >> arr[i].score;
	}

}

void px(nihao * n1)
{
	n1->age +=1;
	if(n1->score *12 <6000)
	{
		s1->score *= 1.2;
	}
	else
	{
		s1->score = 600;
	}
}

void print_out(nihao *n1)
{
	cout << n1->name << " "<< n1->age << " " << (int)n1->score <<endl;
}

int main()
{
	int n;
	in(n);
	for(int i = 1;i<=n;i++)
	{
		px(&arr[i]);
		print_out(&arr[i]);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值