- 【编程大题】
小明的实验室有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();
}
}
}