2013年蓝桥杯国赛Java A组部分题解

2013年蓝桥杯国赛Java A组部分题解

emmmmm,渣渣侥幸入围国赛,最近开始入坑国赛题,慢慢啃吧。


1.【结果填空】 填算式

请看下面的算式:
(ABCD - EFGH) * XY = 900
每个字母代表一个0~9的数字,不同字母代表不同数字,首位不能为0。
比如,(5012 - 4987) * 36 就是一个解。
请找到另一个解,并提交该解中 ABCD 所代表的整数。
请严格按照格式,通过浏览器提交答案。
注意:只提交 ABCD 所代表的整数,不要写其它附加内容,比如:说明性的文字。

分析:简单暴力求解,蓝桥0-9的判断日常~
答案:6048

3.【结果填空】 埃及分数

古埃及曾经创造出灿烂的人类文明,他们的分数表示却很令人不解。古埃及喜欢把一个分数分解为类似: 1/a + 1/b 的格式。
这里,a 和 b 必须是不同的两个整数,分子必须为 1
比如,2/15 一共有 4 种不同的分解法(姑且称为埃及分解法):
1/8 + 1/120
1/9 + 1/45
1/10 + 1/30
1/12 + 1/20
那么, 2/45 一共有多少个不同的埃及分解呢(满足加法交换律的算同种分解)? 请直接提交该整数(千万不要提交详细的分解式!)。
请严格按照要求,通过浏览器提交答案。
注意:只提交分解的种类数,不要写其它附加内容,比如:说明性的文字

分析:暴力分数运算,采用结果2/45-op1=op2的判断方法,不同的分解则再判断下op1>op2.

答案: 7

4.【编程大题】 约数倍数选卡片

闲暇时,福尔摩斯和华生玩一个游戏:
在N张卡片上写有N个整数。两人轮流拿走一张卡片。要求下一个人拿的数字一定是前一个人拿的数字的约数或倍数。例如,某次福尔摩斯拿走的卡片上写着数字“6”,则接下来华生可以拿的数字包括:
1,2,3, 6,12,18,24 ….
当轮到某一方拿卡片时,没有满足要求的卡片可选,则该方为输方。
请你利用计算机的优势计算一下,在已知所有卡片上的数字和可选哪些数字的条件下,怎样选择才能保证必胜!
当选多个数字都可以必胜时,输出其中最小的数字。如果无论如何都会输,则输出-1。
输入数据为2行。第一行是若干空格分开的整数(每个整数介于1~100间),表示当前剩余的所有卡片。
第二行也是若干空格分开的整数,表示可以选的数字。当然,第二行的数字必须完全包含在第一行的数字中。
程序则输出必胜的招法!!

例如:
用户输入:
2 3 6
3 6
则程序应该输出:
3

再如:
用户输入:
1 2 2 3 3 4 5
3 4 5
则程序应该输出:
4

资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

分析:蓝桥杯也超喜欢博弈论,尤其是结合递归模拟求解的那种,博弈论这块可能自己掌握的不够,一开始做的时候用的一维数组,本来想利用局部变量的性质进行求解,不过有点迷,我dfs的ArrayList参数在返回上一层的时候竟然改变了。。后来从大神博客中了解到用hash存卡牌数字出现的次数,用二位数组dfs…TAT(突然想放一张图:我离大佬就差那么一点.jpg】

Ps: 此题可以去蓝桥官网的评测系统去测试

Java代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;


public class Main {
    static ArrayList<Integer> left = new ArrayList<Integer>();
    static ArrayList<Integer> choose = new ArrayList<Integer>();
    static ArrayList<Integer>[] select = new ArrayList[110];
    static int[] cnt = new int[110]; //存1-100每个数字出现的次数
    private static boolean dfs(int x) {
        //返回当前这个人的输赢状态,x为上一个人(对手)上一局所选牌
        for(int j = select[x].size()-1; j>=0; j--){ //倒序遍历,正序超时,参考了大神的代码...
            int num = select[x].get(j);
            if(cnt[num] > 0){
                cnt[num]--;
                boolean flag = dfs(num); //对于当前这个人来说,如果存在选完num后对方必败,则当前是必胜状态
                cnt[num]++;
                if(!flag) return true; 
            }
        }
        return false;
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] str1 = in.nextLine().split(" ");
        String[] str2 = in.nextLine().split(" ");
        for(int i = 0; i<str1.length; i++){
            int num = Integer.parseInt(str1[i]);
            left.add(num); //left存所有卡片
            cnt[num]++;
        }
        for(int i = 0; i<str2.length; i++){
            int num = Integer.parseInt(str2[i]);
            choose.add(num); //choose存第一次可选卡片
        }
        for(int i = 1; i<101; i++){   //select为所有可选卡片,处理后为对应每一个数字,下一个可选数字
            select[i] = new ArrayList<Integer>();
            if(cnt[i] == 0) continue;
            for(int j = 1; j<101; j++){
                if(i%j==0 || j%i==0){
                    select[i].add(j);
                }
            }
        }
        Collections.sort(choose);//排序后从小到大遍历,有满足条件的则输出
        boolean flag = false;
        for(int j = 0; j<choose.size(); j++){
            int x = choose.get(j);
            cnt[x]--;
            if(!dfs(x)){
                flag = true;//找到一种必胜的牌即可退出
                System.out.println(x);
                break;
            }
            cnt[x]++;//否则还原现场
        }
        if(!flag) System.out.println(-1);
    }

}

C++代码

#include<bits/stdc++.h>
using namespace std;
vector<int> lev,choose;
vector<int> total[110];
int ht[110];
bool dfs(int num){
    bool flag = false;
    for(int i = total[num].size()-1; i>=0; i--){
        int x = total[num][i];
            if(ht[x] > 0){
                ht[x]--;
                flag = dfs(x);
                ht[x]++;
                if(!flag) return true;
            }
    }
    return false;
}
int main(){
    string str1,str2;
    getline(cin, str1);
    getline(cin, str2);
    int num = 0;
    for(int i = 0; i<str1.length(); i++){
        char ch = str1[i];
        if(ch == ' '){
            lev.push_back(num);
            ht[num]++;
            num = 0;
        }
        else if(i == str1.length()-1){
            num = num*10+ch-'0';
            ht[num]++;
            lev.push_back(num);
        }
        else {
            num = num*10+ch-'0';
        }
    }
    num = 0;
    for(int i = 0; i<str2.length(); i++){
        char ch = str2[i];
        if(ch == ' '){
            choose.push_back(num);
            num = 0;
        }
        else if(i == str2.length()-1){
            num = num*10+ch-'0';
            choose.push_back(num);
        }
        else {
            num = num*10+ch-'0';
        }
    }
    for(int i = 1; i<101; i++){
        if(!ht[i]) continue;
        for(int j = 1; j<101; j++){
            if(i%j==0 || j%i==0){
                if(ht[j]){
                    total[i].push_back(j);
                }
            }
        }
    }
    sort(choose.begin(), choose.end());
    for(int i = 0; i<choose.size(); i++){
        num = choose[i];
        ht[num]--;
        if(!dfs(num)){
            cout<<num<<endl;
            return 0;
        }
        ht[num]++;
    }
    cout<<-1<<endl;
    return 0;
} 

5.【编程大题】 网络寻路

X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。
源地址和目标地址可以相同,但中间节点必须不同。
如图1所示的网络。
1 -> 2 -> 3 -> 1 是允许的
1 -> 2 -> 1-> 2 或者 1->2->3->2 都是非法的。
输入数据的第一行为两个整数N M,分别表示节点个数和连接线路的条数(1<=N<=10000; 0<=M<=100000)。
接下去有M行,每行为两个整数 u 和 v,表示节点u 和 v 联通(1<=u,v<=N , u!=v)。
输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。
输出一个整数,表示满足要求的路径条数。
例如:
用户输入:
3 3
1 2
2 3
1 3
则程序应该输出:
6
再例如:
用户输入:
4 4
1 2
2 3
3 1
1 4
则程序应该输出:
10
资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

分析:暴力dfs不重写输入流用Scanner在官网的评测系统能得80%的分,不过好像内存测评超过64M了…重写输入流才过,果然算法竞赛C++才是王道a
这里写图片描述
代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    static ArrayList<Integer>[] arr = new ArrayList[10010];
    static boolean[] vis;
    static int m,n,u,v,cnt,st;
    static void dfs(int cur, int step){
        if(step == 3){
            cnt++;
            return;
        }
        for(int i = 0; i<arr[cur].size(); i++){
            int tem = arr[cur].get(i);
            if(tem == st && step!=2) continue;
            if(!vis[tem]){
                vis[tem] = true;
                dfs(tem, step+1);
                vis[tem] = false;
            }
        }
    }
    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        in.nextToken();
        n = (int)in.nval;
        in.nextToken();
        m = (int)in.nval;
        for(int i = 1; i<=n; i++) arr[i] = new ArrayList<>();
        for(int i = 0; i<m; i++){
            in.nextToken();
            u = (int)in.nval;
            in.nextToken();
            v = (int)in.nval;
            arr[u].add(v);
            arr[v].add(u);
        }
        for(int i = 1; i<=n; i++){
            st=i;
            vis = new boolean[n+10];
            dfs(i, 0);
        }
        out.print(cnt);
        out.flush();
    }

}

有待更新…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值