day23 algo121\adv141\143\_147\_169\_189\197\_203\206

ALGO-121. 猴⼦子分苹果

问题描述
秋天到了了,n只猴⼦子采摘了了⼀一⼤大堆苹果放到⼭山洞洞⾥里里,约定第⼆二天平分。这些猴⼦子很崇拜猴王孙悟空,
所以都想给他留留⼀一些苹果。第⼀一只猴⼦子悄悄来到⼭山洞洞,把苹果平均分成n份,把剩下的m个苹果吃了了,
然后藏起来⼀一份,最后把剩下的苹果重新合在⼀一起。这些猴⼦子依次悄悄来到⼭山洞洞,都做同样的操作,
恰好每次都剩下了了m个苹果。第⼆二天,这些猴⼦子来到⼭山洞洞,把剩下的苹果分成n分,巧了了,还是剩下了了
m个。问,原来这些猴⼦子⾄至少采了了多少个苹果。
输⼊入格式
两个整数,n m
输出格式
⼀一个整数,表示原来苹果的数⽬目
样例例输⼊入
5 1
样例例输出
15621
数据规模和约定
0<m<n<9

#include <iostream>
using namespace std;
int m, n;
int check(int num) {
for (int i = 0; i < n; i++) {
if (num % (n-1) == 0) num = num / (n-1) * n + m;
else return 0;
}
return num;
}
int main() {
cin >> n >> m;
for (int i = 0;; i++) {
int num = i * n + m;
if (check(num)) {
cout << check(num);
return 0;
}
}
}

ADV-203. 8皇后·改!!!

问题描述
规则同8皇后问题,但是棋盘上每格都有⼀一个数字,要求⼋八皇后所在格⼦子数字之和最⼤大。
输⼊入格式
⼀一个8*8的棋盘。
输出格式
所能得到的最⼤大数字和
样例例输⼊入
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
48 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
样例例输出
260
数据规模和约定
棋盘上的数字范围0~99

#include <iostream>
#include <cmath>
using namespace std;
int maxvalue = 0;
int pic[8][8];
bool issafe(int pos[], int row) {
for(int i = 0; i < row; i++) {
if(pos[i] == pos[row] || abs(i - row) == abs(pos[i] -
pos[row]))
return false;
return true;
}
void dfs(int pos[], int row) {
if(row == 8) {
int sum = 0;
for(int i = 0; i < 8; i++) {
sum += pic[i][pos[i]];
}
maxvalue = sum > maxvalue ? sum : maxvalue;
return ;
}
for(pos[row] = 0; pos[row] < 8; pos[row]++) {
if(issafe(pos, row)) {
dfs(pos, row + 1);
}
}
}
int main() {
int pos[8];
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
cin >> pic[i][j];
}
}
dfs(pos, 0);
cout << maxvalue;
return 0;
}
}

ADV-197. P1001!!

当两个⽐比较⼤大的整数相乘时,可能会出现数据溢出的情形。为避免溢出,可以采⽤用字符串串的⽅方法
来实现两个⼤大数之间的乘法。
具体来说,⾸首先以字符串串的形式输⼊入两个整数,每个整数的⻓长度不不会超过8位,然后把它们相乘的结果
存储在另⼀一个字符串串当中
(⻓长度不不会超过16位),最后把这个字符串串打印出来。例例如,假设⽤用户输⼊入为:62773417和
12345678,
则输出结果为:774980393241726.
输⼊入:
  62773417 12345678
输出:
774980393241726

分析:
注意char数组的填充是用for循环进行填充
模拟乘法的运算过程,注意相加的过程,它是斜着相加的
最后要找到不为零的头部

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int main(){
	string a,b;
	cin>>a>>b;
	int lena=a.length();
	int lenb=b.length();
	char d[20][20];
	char c[20];
	for (int i = 0; i <= 19; i++) {
for (int j = 0; j <= 19; j++) {
d[i][j] = '0';
}
c[i] = '0';
}
	int temp=0;
	int k=0;
	int cou=0;
	int t=0;
	for(int i=lenb-1;i>=0;i--){
		k=0;
		for(int j=lena-1;j>=0;j--){
			t=((b[i]-'0')*(a[j]-'0'));
			temp=temp+t*pow(10,k++);
		}
		k=0;
		while(temp!=0){
			d[cou][k++]=(temp%10)+'0';
			temp/=10;
		}
		cou++;
	}
	for(int i=0;i<=18;i++){
		temp=0;
		for(int j=0;j<=i;j++){
			c[i]=(c[i]-'0'+d[j][i-j]-'0')%10+'0';
			temp=temp+(d[j][i-j]-'0');
		}
		temp/=10;
		c[i+1]=temp+'0';
	}
	int flag=0;
	for(int i=19;i>=0;i--){
		if(c[i]!='0'){
			flag=i;
			break;
		}
	}
	for(int i=flag;i>=0;i--){
		cout<<c[i];
	}
	return 0;
}

直接用int数组进行储存

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
 int main(){
 	string a,b;
 	cin>>a>>b;
 	int lena=a.length();
 	int lenb=b.length();
 	int d[20][20]={0};
 	int c[20]={0};
 	int temp=0,t,k,ceng=0;
 	for(int i=lenb-1;i>=0;i--){
 		k=0;
 		for(int j=lena-1;j>=0;j--){
 			t=(a[i]-'0')*(b[j]-'0');
 			temp+=t*pow(10,k++);
		 }
		k=0;
		while(temp){
			d[ceng][k++]=temp%10;
			temp/=10;
		}
		ceng++;
	 }
	 for(int i=0;i<19;i++){
	 	temp=0;
	 	for(int j=0;j<=i;j++){
	 		c[i]=(c[i]+d[j][i-j])%10;
	 		temp+=d[j][i-j];
		 }
		 c[i+1]=temp/10;
	 }
	 int flag=0;
	 for(int i=19;i>=0;i--){
	 	if(c[i]!=0)
	 	{
	 		flag=i;
	 		break;
		 }
	 }
	 for(int i=flag;i>=0;i--)
	 	cout<<c[i];
	return 0; 
 }

ADV-147. 学霸的迷宫!!

问题描述
  学霸抢⾛走了了⼤大家的作业,班⻓长为了了帮同学们找回作业,决定去找学霸决⽃斗。但学霸为了了不不要别⼈人
打扰,住在⼀一个城堡⾥里里,城堡外⾯面是⼀一个⼆二维的格⼦子迷宫,要进城堡必须得先通过迷宫。因为班⻓长还
有妹⼦子要陪,磨⼑刀不不误砍柴功,他为了了节约时间,从线⼈人那⾥里里搞到了了迷宫的地图,准备提前计算最短
的路路线。可是他现在正向妹⼦子解释这件事情,于是就委托你帮他找⼀一条最短的路路线。
输⼊入格式
  第⼀一⾏行行两个整数n, m,为迷宫的⻓长宽。
接下来n⾏行行,每⾏行行m个数,数之间没有间隔,为0或1中的⼀一个。0表示这个格⼦子可以通过,1表示
不不可以。假设你现在已经在迷宫坐标(1,1)的地⽅方,即左上⻆角,迷宫的出⼝口在(n,m)。每次移动时只能向
上下左右4个⽅方向移动到另外⼀一个可以通过的格⼦子⾥里里,每次移动算⼀一步。数据保证(1,1),(n,m)可以通
过。
输出格式
  第⼀一⾏行行⼀一个数为需要的最少步数K。
  第⼆二⾏行行K个字符,每个字符∈{U,D,L,R},分别表示上下左右。如果有多条⻓长度相同的最短路路径,选择
在此表示⽅方法下字典序最⼩小的⼀一个。
样例例输⼊入
Input Sample 1:
3 3
001
100
110
Input Sample 2:
3 3
000
000
000
样例例输出
Output Sample 1:
4
RDRD
Output Sample 2:
4
DDRR
数据规模和约定
  有20%的数据满⾜足:1<=n,m<=10
  有50%的数据满⾜足:1<=n,m<=50
  有100%的数据满⾜足:1<=n,m<=500。

思考:
用广度优先算法

ADV-206. 不不⼤大的数!

问题描述
在当今的⼤大数据时代,超⼤大数的⾼高精度计算已经成为众多领域的热⻔门研究之⼀一。现在T校也想在此领域
有所造诣已造福于全社会,然⽽而由于时间有限,所以短时间内难以找出⼤大数计算的通⽤用算法,于是学
校找到了了同学中的“神霸”——你来帮忙,并仅要求你能在数并不不算⼤大的时候给出结果。⼜又出于某种特
殊需要,也并不不要求你给出数的全部结果,⽽而只是要求结果的前10位(注意不不是后10位),并考虑到2的幂次的特殊性和典型性,所以要你计算的数均为2的幂次。
输⼊入格式
⼀一个⾃自然数n。
输出格式
2的n次幂的前10位。
样例例1 输⼊入
60
样例例1 输出
1152921504
样例例2 输⼊入
60000
样例例2 输出
6305794870
数据规模和约定
0<=n<=10000000

分析:
1.当乘以2的次数超过或者等于34次的时候,就会超过10位数字。⽤用⼀一个double型变量量保存要求的
数,然后再最后转为long long int 型。(⾄至于为什什么要⽤用double型,因为第⼆二步的除以1000相当于乘
以1024,为了了避免失去精度使得除法运算后的结果被转为int后不不精准~~)为了了防⽌止超过10位数字,这
个时候可以采取除法的⽅方式让它位数控制在double的不不溢出范围之内~~
2.已知2的10次⽅方是1024,也就是说对于每⼀一个是10的倍数i,就相当于给要求的数增加了了1024倍,这
个时候可以采取除以1000的⽅方式保证它不不溢出~
3.但是因为数据规模太⼤大了了,有⼀一千万⼤大⼩小,所以每⼀一个1024/1000=1.024,当乘以1.024的个数超过
97次⽅方的时候(1.024^97 = 9.979201547674),就会等于让要求的数乘以了了10.为了了保证不不溢出,可以
在乘以了了每970个2的时候,让要求的数除以10保证不不会溢出~(如果想要更更精准的可以⽤用计算器器得
到:1.024^97.1 = 10.00289683498)就是每乘以971个2后除以10~
4.此时⽤用上述办法得到的数如果在数据规模⼤大的时候可能会有10位或者11位,这时候可以统计⼀一下这
个double型数字的位数,然后进⾏行行除以10的运算把它变为前⾯面只有10位数。
5.此时转换为long long int型输出即可~

#include<iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	double t=1.0;
	for(int i=1;i<=n;i++){
		t=t*2;
		if(i>=34&&i%10==0){
			t/=1000;
		}
		if(i%971==0)
			t/=10;
	}
	long long int temp=t;
	int sum=0;
	while(temp){
		temp=temp/10;
		sum++;
	}
	while(sum>10){
		t/=10;
		sum--;
	}
	long long int d=t;
	printf("%lld",d);
	return 0;
}

ADV-143. 扶⽼老老奶奶过街!

⼀一共有5个红领⼱巾,编号分别为A、B、C、D、E,⽼老老奶奶被他们其中⼀一个扶过了了⻢马路路。
五个红领⼱巾各⾃自说话:
A :我和E都没有扶⽼老老奶奶
B :⽼老老奶奶是被C和E其中⼀一个扶过⼤大街的
C :⽼老老奶奶是被我和D其中⼀一个扶过⼤大街的
D :B和C都没有扶⽼老老奶奶过街
E :我没有扶⽼老老奶奶
已知五个红领⼱巾中有且只有2个⼈人说的是真话,请问是谁扶这⽼老老奶奶过了了街?
若有多个答案,在⼀一⾏行行中输出,编号之间⽤用空格隔开。
例例如
A B C D E(这显然不不是正确答案)

思考:
设这五个人为abcde,分别列出这五个人说真话的条件,一个一个去试,判断他们说话为真的个数是否为2,即说的是真话

#include<iostream>
using namespace std;
int main(){
	for(int i=0;i<5;i++){
		int a[5]={0};
		a[i]=1;
		int sum=0;
		if(a[0]==0&&a[4]==0)
			sum++;
		if(a[2]==1&&a[4]==1)
			sum++;
		if(a[2]==1&&a[3]==1)
			sum++;
		if(a[1]==0&&a[2]==0)
			sum++;
		if(a[4]==1)
			sum++;
		if(sum==2)
			cout<<(char)('A'+i)<<" ";
	}
	return 0;
}

ADV-141. 判断名次!

问题描述
某场⽐比赛过后,你想要知道A~E五个⼈人的排名是什什么,于是要求他们每个⼈人说了了⼀一句句话。(经典的开
头……-_-!)得了了第1名的⼈人23,说了了假话;得了了第5名的⼈人不不好意思,也说了了假话;为了了使求解问题简
单,第3名同样说了了假话。(奇数名次说假话)
输⼊入格式
共5⾏行行,各⾏行行依次表示A~E说的话。
每⾏行行包含⼀一个形如“A>=3”的名次判断,即⼀一个⼤大写字⺟母+关系运算符+⼀一个数字,不不包含空格。
⼤大写字⺟母AE,关系运算<、<=、=、>=、>、!=,数字15。注意:等于是“=”不不是“==”!
输出格式
可能有多解,请按照字典序输出排名序列列,每个解⼀一⾏行行
最后⼀一⾏行行输出解的数量量
样例例输⼊入
A=2
D=5
E>3
A>2
B!=1
样例例输出
ACDEB
AECBD
BADCE
BCADE
BDACE
CEADB
CEBDA
7
分析:1.⽤用全排列列公式,枚举除所有可能的排序,检查每个排序是否符合要求
2.检查每种名次,如果出现了了奇数名次的⼈人说了了真话,该序列列不不符合,如果偶数名次的⼈人说了了假话,
也不不符合~

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
string ranks="ABCDE";
vector<string> say(5);
int cnt=0;
bool check(string s){
	int hash[150]={0};
	for(int i=0;i<5;i++)
		hash[s[i]]=i+1;
	for(int i=0;i<5;i++){
		string sayt=say[i];
		int len=sayt.length();
		if(hash['A'+i]%2==1){
			if(sayt[1]=='='&&hash[sayt[0]]==sayt[len-1]-'0')
			return false;
			if(sayt[1]=='!'&&hash[sayt[0]]!=sayt[len-1]-'0')
			return false;
			if(len==3&&sayt[1]=='>'&&hash[sayt[0]]>sayt[len-1]-'0')
			return false;
			if(len==3&&sayt[1]=='<'&&hash[sayt[0]]<sayt[len-1]-'0')
			return false;
			if(len==4&&sayt[1]=='<'&&hash[sayt[0]]<=sayt[len-1]-'0')
			return false;
			if(len==4&&sayt[1]=='>'&&hash[sayt[0]]>=sayt[len-1]-'0')
			return false;
		}else{
			if(sayt[1]=='='&&hash[sayt[0]]!=sayt[len-1]-'0')
			return false;
			if(sayt[1]=='!'&&hash[sayt[0]]==sayt[len-1]-'0')
			return false;
			if(len==3&&sayt[1]=='>'&&hash[sayt[0]]<=sayt[len-1]-'0')
			return false;
			if(len==3&&sayt[1]=='<'&&hash[sayt[0]]>=sayt[len-1]-'0')
			return false;
			if(len==4&&sayt[1]=='<'&&hash[sayt[0]]>sayt[len-1]-'0')
			return false;
			if(len==4&&sayt[1]=='>'&&hash[sayt[0]]<sayt[len-1]-'0')
			return false;
		}
	}
	cnt++;
	return true;
	
}
int main(){
	for(int i=0;i<5;i++)
		cin>>say[i];
	do{
		if(check(ranks)) cout<<ranks<<endl;
	}while(next_permutation(ranks.begin(),ranks.end()));
	cout<<cnt;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值