【C++ / Java】蓝桥杯 —— 基础练习 BASIC



BASIC-3 基础练习 字母图形

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T7


问题描述

利用字母可以组成一些美丽的图形,下面给出了一个例子:

ABCDEFG

BABCDEF

CBABCDE

DCBABCD

EDCBABC

这是一个5行7列的图形,请找出这个图形的规律,并输出一个n行m列的图形。



输入格式

输入一行,包含两个整数n和m,分别表示你要输出的图形的行数的列数。



输出格式

输出n行,每个m个字符,为你的图形。



样例输入

5 7



样例输出

ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC



数据规模与约定

1 <= n, m <= 26。




思路: i == j 的位置永远是 ‘A’ 。在该位置右边,即 j > i 时,是从左到右递增的字母序列;在该位置左边,即 j < i ,是从右到左递增的字母序列。所以,字母的序号与两个坐标的差的绝对值有关。


C++ Code:

#include <iostream>
#include <cmath>
using namespace std;
char a[30][30];
int main(){
	int n,m;	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)
			cout<<char('A'+abs(j-i));
		cout<<endl;
	}
	return 0;
}

Java Code:

import java.util.Scanner;
import java.math.*;
public class Main {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int m = cin.nextInt();
		for(int i=1; i<=n; i++) {
			for(int j=1; j<=m; j++)
				System.out.print((char)('A'+Math.abs(i-j)));
			System.out.println();
		}
	}
}


BASIC-14 基础练习 时间转换

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T54


问题描述

给定一个以秒为单位的时间t,要求用 “< H > : < M > : < S >”的格式来表示这个时间。< H > 表示时间,< M > 表示分钟,而 < S > 表示秒,它们都是整数且没有前导的“0”。例如,若t=0,则应输出是“0:0:0”;若t=3661,则输出“1:1:1”。



输入格式

输入只有一行,是一个整数t(0<=t<=86399)。



输出格式

输出只有一行,是以“ < H > : < M > : < S > ”的格式所表示的时间,不包括引号。



样例输入

0



样例输出

0:0:0



样例输入

3661



样例输出

1:1:1



样例输入

5436



样例输出

1:30:36




思路: 水题,直接取余即可。


Java Code:

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		int y = t / 3600;
		t = t % 3600;
		int m = t / 60;
		t = t % 60;
		int s = t;
		System.out.println(y + ":" + m + ":" + s);
	}
}


BASIC-15 基础练习 字符串对比

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T56


问题描述

给定两个仅由大写字母或小写字母组成的字符串(长度介于1到10之间),它们之间的关系是以下4中情况之一:
  1:两个字符串长度不等。比如 Beijing 和 Hebei
  2:两个字符串不仅长度相等,而且相应位置上的字符完全一致(区分大小写),比如 Beijing 和 Beijing
  3:两个字符串长度相等,相应位置上的字符仅在不区分大小写的前提下才能达到完全一致(也就是说,它并不满足情况2)。比如 beijing 和 BEIjing
  4:两个字符串长度相等,但是即使是不区分大小写也不能使这两个字符串一致。比如 Beijing 和 Nanjing
  编程判断输入的两个字符串之间的关系属于这四类中的哪一类,给出所属的类的编号。



输入格式

包括两行,每行都是一个字符串



输出格式

仅有一个数字,表明这两个字符串的关系编号



样例输入

BEIjing
beiJing



样例输出

3




思路: 直接用 Java 的Api 。


Java Code:

import java.util.Scanner;

public class Main {
	static int[] ans = new int[10];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		String s1 = cin.next();
		String s2 = cin.next();
		if(s1.length() != s2.length())
			System.out.println(1);
		else {
			if(s1.equals(s2))
				System.out.println(2);
			else {
				if(s1.toLowerCase().equals(s2.toLowerCase()))
					System.out.println(3);
				else
					System.out.println(4);
			}
		}
	}
}


BASIC-16 基础练习 分解质因数

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T57


问题描述

求出区间[a,b]中所有整数的质因数分解。



输入格式

输入两个整数a,b。



输出格式

每行输出一个数的分解,形如k=a1a2a3…(a1<=a2<=a3…,k也是从小到大的)(具体可看样例)



样例输入

3 10



样例输出

3=3
4=22
5=5
6=2
3
7=7
8=222
9=33
10=2
5



提示

先筛出所有素数,然后再分解。



数据规模与约定

2<=a<=b<=10000




思路: 这道题跟 蓝桥杯1137 算法提高 质因数 那道题几乎一样,只不过这道题多了一个区间。直接遍历到 sqrt(n) ,如果 n 不是素数且 n 存在质数 i ,则输出该质数,同时 n/=i,此时 i-- ,为了输出所有相同的质数。


Java Code:

import java.util.Scanner;
public class Main {
	static boolean isprime(int n) {
		for(int i=2;i*i<=n;i++) {
			if(n%i==0)	return false;
		}
		return true;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int a = cin.nextInt();
		int b = cin.nextInt();
		for(int i=a;i<=b;i++) {
			System.out.print(i+"=");
			int x=i;
			for(int j=2;j*j<=x && !isprime(x);j++) {
				if(isprime(j) && x%j==0) {
					System.out.print(j+"*");
					x/=j;
					j--;
				}
			}
			System.out.println(x);
		}
	}
}


BASIC-17 基础练习 矩阵乘法

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T58


问题描述

给定一个N阶矩阵A,输出A的M次幂(M是非负整数)
例如:
  A =
  1 2
  3 4
  A的2次幂
  7 10
  15 22



输入格式

第一行是一个正整数N、M(1<=N<=30, 0<=M<=5),表示矩阵A的阶数和要求的幂数。接下来N行,每行N个绝对值不超过10的非负整数,描述矩阵A的值



输出格式

输出共N行,每行N个整数,表示A的M次幂所对应的矩阵。相邻的数之间用一个空格隔开



样例输入

2 2
1 2
3 4



样例输出

7 10
15 22




思路: 可以分为三种情况,0 次幂、1次幂、2次幂及以上。任意矩阵的 0 次幂肯定是单位矩阵,1次幂就是矩阵本身,2次幂及以上就要进行 m 次运算,具体见代码。


Java Code:

import java.util.Scanner;
public class Main {
	static int[][] a = new int[35][35];
	static int[][] b = new int[35][35];
	static int[][] t = new int[35][35];
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		int m = cin.nextInt();
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) {
				a[i][j] = cin.nextInt();
				b[i][j] = a[i][j];
			}
		if(m==0) {	//矩阵的0次幂为单位矩阵
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					if(i==j)	System.out.print(1+" ");
					else	System.out.print(0+" ");
				}
				System.out.println();
			}
			System.out.println();
			System.exit(0);
		}
		if(m==1) {	//矩阵的1次幂为其本身
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) 
					System.out.print(a[i][j]+" ");
				System.out.println();
			}
			System.out.println();
			System.exit(0);
		}
		while(m>=2) {	//矩阵2次幂及以上需要运算m次
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					int k=n;
					while(k>0) {
						t[i][j] += b[i][k]*a[k][j];
						k--;
					}
				}
			}
			for(int i=1;i<=n;i++) {
				for(int j=1;j<=n;j++) {
					b[i][j]=t[i][j];
					t[i][j]=0;
				}
			}
			m--;
		}
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
				System.out.print(b[i][j]+" ");
			}
			System.out.println();
		}
		System.out.println();
	}
}


BASIC-19 基础练习 完美的代价

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T60


问题描述

回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)



输入格式

第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母



输出格式

如果可能,输出最少的交换次数。
否则输出Impossible



样例输入

5
mamad



样例输出

3




思路:

1. 出现“impossible” 的两种情况:

(1)字符串是偶数长度,且有一个奇数个数的字符,那么不可能构成回文串。

(2)有两个及两个以上奇数个数的字符且字符串长度为奇数,也不可能构成回文串。

2. 最小交换次数的情况:

(1)如果 n 为偶数,那么从第一字符开始,从后往前找第一个和它相同的字符,如果找了,就将找到的字符交换到最后一个位置,同时累加每次交换的次数。在下一次遍历时,从第二个字符开始,从倒数第二个字符开始遍历,执行和上述相同的操作;

(2)如果 n 为奇数,在字符串的某一个位置找到了那个出现次数为奇数的字符,先计算它到中间位置需要交换的次数,然后累加到 cnt 中,将剩下的字符都交换到对称后,再交换这个字符即可。


C++ Code:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int main(){
	ios::sync_with_stdio(0);
	int n;	cin>>n;
	string str;	cin>>str;
	int sum=0;	//sum统计交换的次数 
	int vis=0;	//vis判断是否已经有一个奇数个数的字符
	int k=n-1;	//暂存 
	for(int i=0;i<k;i++){	//左指针遍历到第二个字符 
		for(int j=k;j>=i;j--){	//右指针遍历到i 
			if(j==i){	//如果找不到相同的字符 
			//如果字符串偶数长度且有一个奇数个数的字符 或者 有两个及两个以上的奇数个数的字符且字符串长度为奇数 
				if( !(n%2) || vis ){	
					cout<<"Impossible"<<endl;	 
					return 0;
				}
				vis=1;	//标记 
				sum+=(n/2-i);	//奇数个数字符移到中间的步数 
			}
			else if(str[j]==str[i]){	//如果找到相同字符 
				for(int t=j;t<k;t++){	 
					swap(str[t],str[t+1]);	//把str[j]换到str[k] 
					sum++;	//每交换一次,计数一次 
				}
				k--;	//右指针左移 
				break;
			}
		}
	}
	cout<<sum<<endl;
	return 0;
}

Java Code:

import java.util.Scanner;
public class Main {
	static char[] s;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		in.nextLine();
		s = in.nextLine().toCharArray();
		in.close();
		int cnt=0;
		int k=n-1;
		boolean vis = false;
		for(int i=0;i<n;i++) {
			for(int j=k;j>=i;j--) {
				if(j==i) {
					if(n%2==0 || vis) {
						System.out.println("Impossible");
						return;
					}
					vis = true;
					cnt += (n/2-i);
				}
				else if(s[i]==s[j]) {
					for(int t=j;t<k;t++) {
						swap(t,t+1);
						cnt++;
					}
					k--;
					break;
				}
			}
		}
		System.out.println(cnt);
	}
	private static void swap(int x,int y) {
		char temp = s[x];
		s[x] = s[y];
		s[y] = temp;
	}
}


BASIC-21 基础练习 Sine之舞

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T62


问题描述

最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数基本功。所以他准备和奶牛们做一个“Sine之舞”的游戏,寓教于乐,提高奶牛们的计算能力。
不妨设
  An=sin(1–sin(2+sin(3–sin(4+…sin(n))…)
  Sn=(…(A1+n)A2+n-1)A3+…+2)An+1
FJ想让奶牛们计算Sn的值,请你帮助FJ打印出Sn的完整表达式,以方便奶牛们做题。



输入格式

仅有一个数:N<201。



输出格式

请输出相应的表达式Sn,以一个换行符结束。输出中不得含有多余的空格或换行、回车符。



样例输入

3



样例输出

((sin(1)+3)sin(1–sin(2))+2)sin(1–sin(2+sin(3)))+1




思路: 这道题有两种做法,可以暴力模拟,也可以按规律来递归调用。
1. 暴力做法就是直接遍历从左到右输出字符串。
2. 用规律来递归调用:
(1)先出现的是左括号
(2)然后出现的是An
(3)然后出现的是加减号
(4)接着出现的是 一个有规律的数 m-i+1
(5)最后出现的是右括号(最后一个数除外,即最后一个不包含右括号)


C++ Code1: 暴力模拟

#include <iostream>
using namespace std;
int main(){
	int n;	cin>>n;
	for(int i=1;i<n;i++)
		cout<<"(";
	for(int i=1;i<=n;i++){
		if(i==1)
			cout<<"sin(1)";
		else{
			cout<<"sin(1-sin(2";
			for(int j=3;j<=i;j++){
				if(j%2==0)
					cout<<"-";
				else
					cout<<"+";
				cout<<"sin("<<j;
			}
			for(int j=1;j<=i;j++)
				cout<<")";
		}
		cout<<"+"<<n-i+1;
		if(i!=n)
			cout<<")";
	}
} 

C++ Code2: 递归做法

#include <iostream>
using namespace std;
void An(int k){		//输出An 
	for(int i=1;i<=k;i++){
		cout<<"sin("<<i;
		if(i==k)
			break;
		else{
			if(i%2==1)
				cout<<"-";
			else
				cout<<"+";
		}
	}
	for(int i=1;i<=k;i++)
		cout<<")";
}
void Sn(int m){		//输出Sn 
	for(int i=1;i<m;i++)
		cout<<"(";
	for(int i=1;i<=m;i++){
		An(i);
		cout<<"+"<<m-i+1;
		if(i!=m)
			cout<<")";
	}
}
int main(){
	int n;	cin>>n;
	Sn(n);
	return 0;
}


BASIC-22 基础练习 FJ的字符串

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T63


问题描述

FJ在沙盘上写了这样一些字符串:
  A1 = “A”
  A2 = “ABA”
  A3 = “ABACABA”
  A4 = “ABACABADABACABA”
  … …
你能找出其中的规律并写所有的数列AN吗?



输入格式

仅有一个数:N ≤ 26。



输出格式

请输出相应的字符串AN,以一个换行符结束。输出中不得含有多余的空格或换行、回车符。



样例输入

3



样例输出

ABACABA




思路: 这种找规律题一定不要自己像规律,很容易就把题意想错,应该多运行几个结果找规律。
在这里插入图片描述
从结果显示可以发现规律:

第一个为A,

第二个在A的基础上加上B,再加第一个 ,即ABA

第三个在第二个的基础上加上C,再加第二个,即ABACABA

注意:输出 ‘A’+x-1 时不要用 cout 输出格式,会输出数字,应该用 printf 输出格式。


C++ Code:

#include <iostream>
#include <cstdio>
using namespace std; 
void f(int x){
	if(x==1)
		cout<<'A';
	else{
		f(x-1);
		printf("%c",'A'+x-1);
		f(x-1);
	}
}
int main(){
	int n;	cin>>n;
	f(n);
	return 0;
}

Java Code:

import java.util.Scanner;
public class Main {
	public static void f(int x) {
		if(x==1)
			System.out.print('A');
		else {
			f(x-1);
			System.out.print((char)('A'-1+x));
			f(x-1);
		}
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		f(cin.nextInt());
	}
}


BASIC-23 基础练习 芯片测试

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T64


问题描述

有n(2≤n≤20)块芯片,有好有坏,已知好芯片比坏芯片多。每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时,能正确给出被测试芯片是好还是坏。而用坏芯片测试其他芯片时,会随机给出好或是坏的测试结果(即此结果与被测试芯片实际的好坏无关)。

给出所有芯片的测试结果,问哪些芯片是好芯片。



输入格式

输入数据第一行为一个整数n,表示芯片个数。
第二行到第n+1行为n*n的一张表,每行n个数据。表中的每个数据为0或1,在这n行中的第i行第j列(1≤i, j≤n)的数据表示用第i块芯片测试第j块芯片时得到的测试结果,1表示好,0表示坏,i=j时一律为1(并不表示该芯片对本身的测试结果。芯片不能对本身进行测试)。



输出格式

按从小到大的顺序输出所有好芯片的编号



样例输入

3
1 0 1
0 1 0
1 0 1



样例输出

1 3




思路:

  1. 题意理解:好芯片比坏芯片多,且用好芯片测试其他芯片能正确给出被测试芯片是好还是坏,说明对于每块好芯片,至少有 n/2 块好芯片能测出其是好的,即测出结果为1。
  2. 那么只要遍历每块被测试芯片,只要满足测试结果为1的数目大于等于 n/2(不包括测试自己的结果)。
  3. 第 i 行第 j 列的数据表示用第 i 块芯片测试第 j 块芯片,因此每一列的数据表示每块芯片被测试的结果。

C++ Code:

#include <iostream>
#include <algorithm>
using namespace std;
int a[25][25];
int sum[25];
int main(){
	int n;	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>a[i][j];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i!=j && a[i][j]==1)
				sum[j]++;
		}
	}
	for(int j=1;j<=n;j++){
		if(sum[j]>=n/2)
			cout<<j<<" ";
	}
	return 0;
}

Java Code:

import java.util.Scanner;
public class Main {
	static int[][] a = new int[25][25];
	static int[] sum = new int[25];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				a[i][j] = in.nextInt();
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i!=j && a[i][j]==1)
					sum[j]++;
			}
		}
		for(int j=1;j<=n;j++){
			if(sum[j]>=n/2)
				System.out.print(j + " ");
		}
	}

}


BASIC-24 基础练习 龟兔赛跑预测

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T65


问题描述

话说这个世界上有各种各样的兔子和乌龟,但是研究发现,所有的兔子和乌龟都有一个共同的特点——喜欢赛跑。于是世界上各个角落都不断在发生着乌龟和兔子的比赛,小华对此很感兴趣,于是决定研究不同兔子和乌龟的赛跑。

他发现,兔子虽然跑比乌龟快,但它们有众所周知的毛病——骄傲且懒惰,于是在与乌龟的比赛中,一旦任一秒结束后兔子发现自己领先t米或以上,它们就会停下来休息s秒。对于不同的兔子,t,s的数值是不同的,但是所有的乌龟却是一致——它们不到终点决不停止。
  
然而有些比赛相当漫长,全程观看会耗费大量时间,而小华发现只要在每场比赛开始后记录下兔子和乌龟的数据——兔子的速度v1(表示每秒兔子能跑v1米),乌龟的速度v2,以及兔子对应的t,s值,以及赛道的长度l——就能预测出比赛的结果。

但是小华很懒,不想通过手工计算推测出比赛的结果,于是他找到了你——清华大学计算机系的高才生——请求帮助,请你写一个程序,对于输入的一场比赛的数据v1,v2,t,s,l,预测该场比赛的结果。



输入格式

输入只有一行,包含用空格隔开的五个正整数v1,v2,t,s,l,其中(v1,v2<=100;t<=300;s<=10;l<=10000且为v1,v2的公倍数)



输出格式

输出包含两行,第一行输出比赛结果——一个大写字母“T”或“R”或“D”,分别表示乌龟获胜,兔子获胜,或者两者同时到达终点。
第二行输出一个正整数,表示获胜者(或者双方同时)到达终点所耗费的时间(秒数)。



样例输入

10 5 5 2 20



样例输出

D
4



样例输入

10 5 5 1 20



样例输出

R
3



样例输入

10 5 5 3 20



样例输出

T
4




思路: 这道题需要有较好的思维模拟能力,要不然真的有点乱。

  1. 当兔子且乌龟都还没到达终点时,分为两种情况,一种就是兔子停下来,判断这时间内乌龟能不能到达终点。一种是兔子不停下来。不断地更新数据。、
  2. 最后根据乌龟和兔子的路程,输出结果。
  3. 要注意的一点就是,这道题不需要考虑是否为浮点数。

C++ Code:

#include <iostream>
#include <algorithm>
using namespace std; 
int main(){
	int v1,v2,t,s,l;
	cin>>v1>>v2>>t>>s>>l;
	int s1=0,s2=0;	//兔子和乌龟的路程
	int t0=0;		//兔子或乌龟到达终点所用的时间 
	while(s1<l && s2<l){
		if(s1-s2>=t){	//兔子停下来 
			if((l-s2)/v2 < s){
				t0+=(l-s2)/v2;
				s2=l;
			}else{
				s2+=v2*s;
				t0+=s;
			}
		}else{	//兔子不停 
			t0++;
			s1+=v1;
			s2+=v2;
		}
	}
	if(s1>s2){
		cout<<'R'<<endl;
		cout<<t0<<endl;
	}else if(s2>s1){
		cout<<'T'<<endl;
		cout<<t0<<endl;
	}else{
		cout<<'D'<<endl;
		cout<<t0<<endl;
	}
	return 0;
}


BASIC-25 基础练习 回形取数(模拟)

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T66


问题描述

回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度。一开始位于矩阵左上角,方向向下。



输入格式

输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列。接下来m行每行n个整数,表示这个矩阵。



输出格式

输出只有一行,共mn个数,为输入矩阵回形取数得到的结果。数之间用一个空格分隔,行末不要有多余的空格。



样例输入

3 3
1 2 3
4 5 6
7 8 9



样例输出

1 4 7 8 9 6 3 2 5



样例输入

3 2
1 2
3 4
5 6



样例输出

1 3 5 6 4 2




思路: 用 while 循环来计算已经输出的数量,然后在这个循环里,以一圈为一个循环,即 “下右上左” 。要用标记数组来标记数是否用过。


Java Code:

import java.util.Scanner;
public class Main {
	static int[][] a = new int[210][210];
	static int[][] vis = new int[210][210];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt(), m = cin.nextInt();
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				a[i][j] = cin.nextInt();
		int cnt = 1, i = 1, j = 1;
		vis[1][1] = 1;
		System.out.print(a[1][1] + " ");
		while (cnt < n*m) {
			
			while (i + 1 <= n && vis[i+1][j] == 0) {
				vis[i+1][j] = 1;
				System.out.print(a[i+1][j] + " ");
				i++;
				cnt++;
			}
			
			while (j + 1 <= m && vis[i][j+1] == 0) {
				vis[i][j+1] = 1;
				System.out.print(a[i][j+1] + " ");
				j++;
				cnt++;
			}
			
			while (i - 1 >= 1 && vis[i-1][j] == 0) {
				vis[i-1][j] = 1;
				System.out.print(a[i-1][j] + " ");
				i--;
				cnt++;
			}
			
			while (j - 1 >= 1 && vis[i][j-1] == 0) {
				vis[i][j-1] = 1;
				System.out.print(a[i][j-1] + " ");
				j--;
				cnt++;
			}
		}
	}
}


BASIC-28 基础练习 Huffuman树

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T69


问题描述

Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
  
给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:
  1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
  2. 重复步骤1,直到{pi}中只剩下一个数。
  在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
  本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。

例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
  1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
  2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
  3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
  4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
  5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。



输入格式

输入的第一行包含一个正整数n(n<=100)。
接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。



输出格式

输出用这些数构造Huffman树的总费用。



样例输入

5
5 3 8 2 9



样例输出

59




思路: 运用优先队列的小顶堆做法,当队列的长度大于1,不断把最小的两个数加入总和 ans,并将该两个数删掉后把其和压入队列。


C++ Code:

#include <iostream>
#include <queue>
using namespace std;
int main(){
	priority_queue<int,vector<int>,greater<int> > q;
	int n;	cin>>n;
	int x;
	for(int i=1;i<=n;i++){
		cin>>x;
		q.push(x);
	}
	int ans=0,sum=0;
	while(q.size()>1){
		ans+=q.top();
		sum+=q.top();
		q.pop();
		ans+=q.top();
		sum+=q.top();
		q.pop();
		q.push(sum);
		sum=0;
	}
	cout<<ans<<endl;
	return 0;
}

Java Code:

//优先队列做法
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
	static PriorityQueue<Integer> q = new PriorityQueue<Integer>();
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		for(int i=0; i<n; i++)
			q.offer(cin.nextInt());
		int ans=0,sum=0;
		while(q.size()>1) {
			sum+=q.poll();
			sum+=q.poll();
			ans+=sum;
			q.offer(sum);
			sum=0;
		}
		System.out.println(ans);
	}
}

Java Code:

//ArrayList集合做法
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<Integer> lst = new ArrayList<Integer>();
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();
		for(int i = 1; i <= n; i++)
			lst.add(cin.nextInt());
		int ans = 0;
		while(lst.size() > 1) {
			Collections.sort(lst);// 给列表排序
			int temp = lst.get(0) + lst.get(1);
			lst.set(0, temp);// 用temp替换掉列表里索引为0的元素
			lst.remove(1);// 移除下标为1的元素
			ans += temp;
			
		}
		System.out.println(ans);
	}
}


BASIC-29 基础练习 高精度加法

原题链接:http://lx.lanqiao.cn/problem.page?gpid=T70


问题描述

输入两个整数a和b,输出这两个整数的和。a和b都不超过100位。



算法描述

由于a和b都比较大,所以不能直接使用语言中的标准数据类型来存储。对于这种问题,一般使用数组来处理。

定义一个数组A,A[0]用于存储a的个位,A[1]用于存储a的十位,依此类推。同样可以用一个数组B来存储b。
  
计算c = a + b的时候,首先将A[0]与B[0]相加,如果有进位产生,则把进位(即和的十位数)存入r,把和的个位数存入C[0],即C[0]等于(A[0]+B[0])%10。然后计算A[1]与B[1]相加,这时还应将低位进上来的值r也加起来,即C[1]应该是A[1]、B[1]和r三个数的和.如果又有进位产生,则仍可将新的进位存入到r中,和的个位存到C[1]中。依此类推,即可求出C的所有位。
  
最后将C输出即可。



输入格式

输入包括两行,第一行为一个非负整数a,第二行为一个非负整数b。两个整数都不超过100位,两数的最高位都不是0。



输出格式

输出一行,表示a + b的值。



样例输入

20100122201001221234567890
2010012220100122



样例输出

20100122203011233454668012




思路: 高精度题目用 C++ 来做比较麻烦,要将其转换为字符串来处理。用 Java 或者 Python 来处理就很简单了。


C++ Code:

#include <bits/stdc++.h>
using namespace std;  
int main()  
{  
  string str1,str2;  
  int a[250],b[250],len;   //数组的大小决定了计算的高精度最大位数  
  int i;  
  memset(a,0,sizeof(a));  
  memset(b,0,sizeof(b));  
  cin>>str1>>str2;   //输入两个字符串  
  a[0]=str1.length();  //取得第一个字符串的长度  
  for(i=1;i<=a[0];i++)  //把第一个字符串转换为整数,存放在数组a中  
    a[i]=str1[a[0]-i]-'0';  
  b[0]=str2.length();   //取得第二个字符串长度  
  for(i=1;i<=b[0];i++)   //把第二个字符串中的每一位转换为整数,存放在数组B中  
    b[i]=str2[b[0]-i]-'0';  
  len=(a[0]>b[0]?a[0]:b[0]);   //取两个字符串最大的长度  
  for(i=1;i<=len;i++)   //做按位加法,同时处理进位  
  {  
    a[i]+=b[i];  
    a[i+1]+=a[i]/10;  
    a[i]%=10;     
  }  
  len++;    //下面是去掉最高位的0,然后输出。  
  while((a[len]==0)&&(len>1)) len--;  
  for(i=len;i>=1;i--)  
    cout<<a[i];  
  return 0;   
}   
//注意:两个数相加,结果的位数,应该比两个数中大的那个数多一位。 

Java Code:

import java.util.Scanner;
import java.math.*;
public class Main {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		BigInteger a = cin.nextBigInteger();
		BigInteger b = cin.nextBigInteger();
		System.out.println(a.add(b));
	}
}

Python Code:

a = int(input())
b = int(input())
print(a+b)


  • 10
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值