蓝桥杯2016Java_A组
1. 煤球数目
/*
煤球数目
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
....
如果一共有100层,共有多少个煤球?
请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
//每一次都比上一层多一个球,2,3,4,5.....
//答案:171700
public class _01煤球数目 {
public static void main(String[] args) {
int pre = 1;
int plus = 2;
long sum = 1;
for(int k = 2 ;k <= 100 ; k++){ //从第二层开始
pre = pre + plus;
sum += pre;
plus++;//一层增一个
}
System.out.println(sum);
}
}
2.生日蜡烛
/*
生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
答案:26
*/
public class _02生日蜡烛 {
public static void main(String[] args) {
// f1(); 方法1
// f2(); 方法2
f3(); //方法3
}
//暴力
static void f3(){
for(int i = 1; i< 100 ; i++){
int sum = i; //每一次从 i 岁开始
for(int j = 1 ; j <= i ; j++){
sum += j;
if(sum==236)
{
System.out.println(i);
break;
}
}
}
}
static void f2(){
for(int i = 1 ; i< 100 ;i++){
for(int j = i ; j < 100 ; j++){
if((i+j)*(j-i+1)/2 == 236){
System.out.print(i);
}
}
}
}
static void f1(){
for(int i = 1 ; i< 100 ; i++){
int t = i*(i-1)/2;
if((236-t)%i == 0){
//输出首项
System.out.println((236-t)/i+" "+i);
}
}
}
}
3. 搭积木
/*
搭积木
小明最近喜欢搭数字积木,
一共有10块积木,每个积木上有一个数字,0~9。
搭积木规则:
每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小。
最后搭成4层的金字塔形,必须用完所有的积木。
下面是两种合格的搭法:
0
1 2
3 4 5
6 7 8 9
0
3 1
7 5 2
9 8 6 4
请你计算这样的搭法一共有多少种?
请填表示总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
//这是判断的条件
//每个积木放到其它 两个积木 的上面,并且一定比 下面 的 两个 积木数字 小。
//答案:768
public class _03搭积木 {
static int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
private static int ans;
public static void main(String[] args) {
f(0);
System.out.println(ans);
}
/*
0
1 2
3 4 5
6 7 8 9
*/
// 全排列
private static void f(int k) {
if (k == 10) {
ans++;
}
for (int i = k; i < 10; i++) {
swap(k, i);
//每个积木放到其它 两个积木 的上面,并且一定比 下面 的 两个 积木数字 小。
//剪枝
if (k==1&&arr[1]<arr[0]||
k==2&&arr[2]<arr[0]||
k==3&&arr[3]<arr[1]||
k==4&&(arr[4]<arr[1]||arr[4]<arr[2])||
k==5&&arr[5]<arr[2]||
k==6&&arr[6]<arr[3]||
k==7&&(arr[7]<arr[3]||arr[7]<arr[4])||
k==8&&(arr[8]<arr[4]||arr[8]<arr[5])||
k==9&&arr[9]<arr[5])
{
swap(k, i);
continue;//跳过
}
f(k + 1);
swap(k, i);
}
}
// 交换
private static void swap(int k, int i) {
int t = arr[i];
arr[i] = arr[k];
arr[k] = t;
}
}
6. 寒假作业
/*
寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果显示不出来,可以参见【图1.jpg】)
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
//答案:64
public class _06寒假作业 {
static int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
static int ans;
public static void main(String[] args) {
f(0);
System.out.println(ans);
}
static void f(int k) {
if (k == 13) {
if (check()) {
ans++;
}
}
for (int i = k; i < 13; i++) {
swap(i, k);
//提前排除,提升效率,剪枝
//一定要用 k等于 那个数 , 不然会出错
if(k == 2 && a[0]+a[1]!=a[2] || k == 5 && a[3]-a[4]!=a[5]){
swap(i, k); //交换回来,如不换回来也会出错
continue;
}
f(k + 1);
swap(i, k);
}
}
static boolean check() {
//有13个数没有用完,因为换来换去最后还是会换到的
if ( a[0] + a[1] == a[2] &&
a[3] - a[4] == a[5] &&
a[6] * a[7] == a[8] &&
a[9] % a[10] == 0 &&
a[9] / a[10] == a[11]) {
return true;
}
return false;
}
// 交换
static void swap(int i, int k) {
int t = a[i];
a[i] = a[k];
a[k] = t;
}
}
7. 剪邮票
/*
剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
//答案:116
public class _07剪邮票 {
static int ans;
//剪下5张,所以有5个1
static int a[] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };
// 它的每个排列代表着12选5的一个方案
public static void main(String[] args) {
int[] path = new int[12];
f(0, path);
System.out.println(ans);
}
static boolean vis[] = new boolean[12];//默认为false
static void f(int k, int path[]) {
if (k == 12) {
if (check(path)) {
ans++;
}
}
for (int i = 0; i < 12; i++) {
if (i > 0 && a[i] == a[i - 1] && !vis[i - 1])
continue;
// 现在准备选取的元素和上一个元素相同,但是上一个元素还没使用
if (!vis[i]) { // 没有被用过的元素可以抓入到path
vis[i] = true; // 标记为已访问
path[k] = a[i]; // 将a[i]填入到path[k]中
f(k + 1, path); // 递归
vis[i] = false;// 回溯
}
}
}
static boolean check(int path[]) {
int g[][] = new int[3][4];
// 将某个排列映射到二维矩阵上
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
if (path[i * 4 + j] == 1) { //每行每列的个个数 true == 1
g[i][j] = 1;
} else {
g[i][j] = 0;
}
}
}
int cnt = 0; // 连通块的数目
// 上面就有5个格子被标记为1,现在才用dfs做连通性检查,要求只有一个连通块
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
if (g[i][j] == 1) {
dfs(g, i, j);
cnt++;
}
}
}
return cnt == 1; //说明为连通
}
static void dfs(int g[][], int i, int j) {
g[i][j] = 0;
if (i - 1 >= 0 && g[i - 1][j] == 1)
dfs(g, i - 1, j); //上
if (i + 1 <= 2 && g[i + 1][j] == 1)
dfs(g, i + 1, j); //下
if (j - 1 >= 0 && g[i][j - 1] == 1)
dfs(g, i, j - 1); //左
if (j + 1 <= 3 && g[i][j + 1] == 1)
dfs(g, i, j + 1); //右
}
}
8.交换瓶子
/*
交换瓶子
有N个瓶子,编号 1 ~ N,放在架子上。
比如有5个瓶子:
2 1 3 5 4
要求每次拿起2个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5
对于这么简单的情况,显然,至少需要交换2次就可以复位。
如果瓶子更多呢?你可以通过编程来解决。
输入格式为两行:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。
输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。
例如,输入:
5
3 1 2 5 4
程序应该输出:
3
再例如,输入:
5
5 4 3 2 1
程序应该输出:
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
*/
public class _08交换瓶子 {
static int n;
static int[] a = new int[10001];
static int ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//处理输入
n = sc.nextInt();
for(int i = 1 ; i <= n ;i++){
a[i] = sc.nextInt();
}
//遍历i : i - N
for(int i = 1 ; i <= n ; i++){
//如果a[i] = i , 已经到位
if(a[i] == i) //就是当前位置对,不用交换
continue;
//否则先找到i在a中的位置pos(i)和i位交换 -- swap(a , pos(i),i)
else{
swap(pos(i) , i); //返回下标后就和当前的下标交换
ans++;
}
}
System.out.println(ans);
}
static int pos(int x){
for(int i = 1 ; i <= n ;i++){
if(a[i] == x) //遍历数组找到 当前数的下标 返回
return i;
}
return -1;
}
//交换
static void swap(int i , int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}