2017年第八届蓝桥杯国赛JavaA组部分题解


  1. 【编程大题】

小明的实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?
输入
第一行包含一个整数N。
以下N行每行两个整数a和b,表示a和b之间有一条数据链接相连。
对于30%的数据,1 <= N <= 1000
对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= N
输入保证合法。
输出
按从小到大的顺序输出在环路上的电脑的编号,中间由一个空格分隔。
样例输入
5
1 2
3 1
2 4
2 5
5 3
样例输出
1 2 3 5


分析:tarjan模板题,入门萌新,其实和并查集有点像。。可以在C语言网上提交测试。

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.Stack;

public class G201701 {
    static int maxn = (int)1e6+10;
    static ArrayList<Integer>[] arr = new ArrayList[maxn]; 
    static int n,u,v;
    static int[] pre =  new int[maxn];
    static int[] lowlink =  new int[maxn];
    static int[] sccno =  new int[maxn];
    static int[] ht =  new int[maxn];
    static int dfs_clock,scc_cnt;
    static Stack<Integer> stack = new Stack<Integer>();
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    static void dfs(int cur, int prev){
        pre[cur] = lowlink[cur] = dfs_clock++;
        stack.push(cur);
        for(int i = 0; i<arr[cur].size(); i++){
            int tem = arr[cur].get(i);
            if(prev == tem) continue;
            if(pre[tem] == 0){
                dfs(tem, cur);
                lowlink[cur] = Math.min(lowlink[cur], lowlink[tem]);
            } else if(sccno[tem] == 0){
                lowlink[cur] = Math.min(lowlink[cur], pre[tem]);
            }
        }

        if(lowlink[cur] == pre[cur]){ //找到祖先
            scc_cnt++;
            while(true){
                int x = stack.pop();
                sccno[x] = scc_cnt;
                if(x == cur) break;
            }
        }
    }
    public static void main(String[] args) throws IOException{
        in.nextToken();
        n = (int)in.nval;
        for(int i = 1; i<=n; i++){
            arr[i] = new ArrayList<>();
        }
        for(int i = 0; i<n; i++){
            in.nextToken();
            u = (int)in.nval;
            in.nextToken();
            v = (int)in.nval;
            arr[u].add(v);
            arr[v].add(u);
        }
        dfs(1, 0);
        int st = 0, cnt=0;
        for(int i = 1; i<=n; i++){
            ht[sccno[i]]++;
            if(ht[sccno[i]] > 1){
                st = sccno[i];
                break;
            }
        }
        for(int i = 1; i<=n; i++){
            if(sccno[i] == st){
                if(cnt != 0) out.print(" ");
                cnt++;
                out.print(i);
                out.flush();
            }
        }
    }

}

2.【编程大题】 填字母游戏

小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。
K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。
并且:
1. 轮到某人填的时候,只能在某个空格中填入L或O
2. 谁先让字母组成了“LOL”的字样,谁获胜。
3. 如果所有格子都填满了,仍无法组成LOL,则平局。
小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。
输入
第一行,数字n(n<10),表示下面有n个初始局面。
接下来,n行,每行一个串,表示开始的局面。
比如:“**”, 表示有6个空格。
“L****”, 表示左边是一个字母L,它的右边是4个空格。
输出
要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
1 表示能赢
-1 表示必输
0 表示可以逼平
样例输入

  4
  ***
  L**L
  L**L***L
  L*****L

样例输出
0
-1
1
1

分析:博弈论典型题目,主要考察递归,一定要注意回溯!!
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.Scanner;

public class G201705 {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    static int n;
    static int res;

    static int dfs(char[] str){
        //返回当前这个人的胜负情况
        String arr = new String(str);
        if(arr.contains("LOL")) return -1;
        if(!(arr.contains("*"))) return 0;
        int tem;
        boolean ping  = false;
        for(int i = 0; i<str.length; i++){
            if(str[i] == '*'){
                try{
                    str[i] = 'L';
                    tem = dfs(str);
                    if(tem == -1) return 1;
                    else if(tem == 0) ping = true;
                    str[i] = 'O';
                    tem = dfs(str);
                    if(tem == -1) return 1;
                    else if(tem == 0) ping = true;
                }
                finally{   //finally一定会执行
                    str[i] = '*'; //一定要复原!!!
                }
            }
        }
        if(ping) return 0;
        return -1;
    }
    public static void main(String[] args) throws IOException{
        Scanner cin = new Scanner(System.in);
        n = cin.nextInt();
        cin.nextLine();
        for(int i = 0; i<n; i++){
            String tem = cin.nextLine();
            res = dfs(tem.toCharArray());
            out.println(res);
            out.flush();
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值