2013编程之美资格赛之传话游戏(Java实现)

简介: 传话游戏 时间限制: 1000ms 内存限制: 256MB 描述 Alice和Bob还有其他几位好朋友在一起玩传话游戏。这个游戏是这样进行的:首先,所有游戏者按顺序站成一排,Alice站第一位,Bob站最后一位。然后,Alice想一句话悄悄告诉第二位游戏者,第二位游戏者又悄悄地告诉第三位,第三位又告诉第四位……以此类推,直到倒数第二位告诉Bob。两位游戏者在传话中,不能让其他人听到,
传话游戏


时间限制: 1000ms 内存限制: 256MB


描述
Alice和Bob还有其他几位好朋友在一起玩传话游戏。这个游戏是这样进行的:首先,所有游戏者按顺序站成一排,Alice站第一位,Bob站最后一位。然后,Alice想一句话悄悄告诉第二位游戏者,第二位游戏者又悄悄地告诉第三位,第三位又告诉第四位……以此类推,直到倒数第二位告诉Bob。两位游戏者在传话中,不能让其他人听到,也不能使用肢体动作来解释。最后,Bob把他所听到的话告诉大家,Alice也把她原本所想的话告诉大家。 


由于传话过程中可能出现一些偏差,游戏者越多,Bob最后听到的话就与Alice所想的越不同。Bob听到的话往往会变成一些很搞笑的东西,所以大家玩得乐此不疲。经过几轮游戏后,Alice注意到在两人传话中,有些词汇往往会错误地变成其他特定的词汇。Alice已经收集到了这样的一个词汇转化的列表,她想知道她的话传到Bob时会变成什么样子,请你写个程序来帮助她。


输入
输入包括多组数据。第一行是整数 T,表示有多少组测试数据。每组数据第一行包括两个整数 N 和 M,分别表示游戏者的数量和单词转化列表长度。随后有 M 行,每行包含两个用空格隔开的单词 a 和 b,表示单词 a 在传话中一定会变成 b。输入数据保证没有重复的 a。最后一行包含若干个用单个空格隔开的单词,表示Alice所想的句子,句子总长不超过100个字符。所有单词都只包含小写字母,并且长度不超过20,同一个单词的不同时态被认为是不同的单词。你可以假定不在列表中的单词永远不会变化。


输出
对于每组测试数据,单独输出一行“Case #c: s”。其中,c 为测试数据编号,s 为Bob所听到的句子。s 的格式与输入数据中Alice所想的句子格式相同。


数据范围
1 ≤ T ≤ 100


小数据:2 ≤ N ≤ 10, 0 ≤ M ≤ 10 


大数据:2 ≤ N ≤ 100, 0 ≤ M ≤ 100 


样例输入
2
4 3
ship sheep
sinking thinking
thinking sinking
the ship is sinking
10 5
tidy tiny
tiger liar
tired tire
tire bear
liar bear
a tidy tiger is tired
样例输出
Case #1: the sheep is thinking
Case #2: a tiny bear is bear




主算法:
define 输出集合L
get T
for 1 to T
get N,M
for 1 to M-1
get 词对
get 会变词集合
把 变化词集合重构为 循环变化词集 和 传递变化词集合
get 变化语句(words)
for-each word word属于words
if 会 变词集合 contains(word)
依据 循环变化词集 和 传递变化词集合 加上N 对word进行变化
L.add(words)
print L

代码:

 
import java.util.*;

public class Main {

	final static int FLAG=-1;
	public static void main(String[] args){
		int T=0;
		int N=0;
		int M=0;
		Scanner sc=new Scanner(System.in);
		T=Integer.valueOf(sc.nextLine());
		String[] list=new String[T];
		
		/*分别对每组数据进行处理*/
		for(int i=0;i<T;i++){
			String str1=sc.nextLine();
			String[] nums=str1.trim().split(" ");
			N=Integer.valueOf(nums[0]);
			M=Integer.valueOf(nums[1]);
			String[][] twoWords=new String[M][2];
			for(int j=0;j<M;j++){
				String str2=sc.nextLine();
				String[] words=str2.trim().split(" ");
				twoWords[j][0]=words[0];;
				twoWords[j][1]=words[1];
			}
			// 要交换的词
			String[]exWords=getExWords(twoWords);
			/* 一下全部是基于词下标的处理*/
			int[][] twos=getTwos(twoWords,exWords);
			/*处理集合,circulate是循环体,transmit是传递体,要是传递体的最后一个元素是-1,那么它是一个复合体*/
			List<List<Integer>> circulate=new ArrayList<List<Integer>>(11);
			List<List<Integer>> transmit=new ArrayList<List<Integer>>(11);
			/* 为处理集合赋值*/
			handleWords(circulate,transmit,twos,exWords);
			
			/* 处理集合所包含的词集*/
			int[] wordsC=getWordSet(circulate);
			int[] wordsT=getWordSet(transmit);
			String sentence=sc.nextLine();
			String[] words=sentence.split(" ");
			
			/*对词进行处理*/
			for(int j=0;j<words.length;j++){
				int temp=getIndex(words[j],exWords);				//把要处理的词变化为可处理词集的编号,要是-1则不处理
				if(words[j].length()>0 && temp!=-1){
			
					if(!disContains(temp,wordsC)){
						/* 要处理的词在循环体词集中*/
						swap(words,j,circulate,N,exWords);
					}else if(!disContains(temp,wordsT)){
						/* 要处理的词在传递体词集中*/
						swap(words,j,circulate,transmit,N,exWords);
					}
				}
			}
			
			/*对处理后的词继续合并*/
			String temp="";
			for(String word:words){
				temp=temp+" "+word;
			}
			
			/* 处理结果合并*/
			list[i]=temp.trim();
		}
		
		/*打印处理结果*/
		printResult(list);
	}

	/*集合中包含的不同词集*/
	private static int[] getWordSet(List<List<Integer>> lists) {
		ArrayList<Integer> temp=new ArrayList<Integer>(11);
		for(List<Integer> list:lists){
			for(int x:list){
				if(!temp.contains(x))
					temp.add(x);
			}
		}
		int[] xs=new int[temp.size()];
		for(int i=0;i<xs.length;i++){
			xs[i]=temp.get(i);
		}
		return xs;
	}

	/*把变化词对进行编号化处理*/
	private static int[][] getTwos(String[][] twoWords, String[] exWords) {
		int[][] temp=new int[twoWords.length][2];
		for(int i=0;i<twoWords.length;i++){
			for(int j=0;j<2;j++){
				temp[i][j]=getIndex(twoWords[i][j],exWords);
			}
		}
		return temp;
	}

	/*把单个词语编号化*/
	private static int getIndex(String str, String[] exWords) {
		int temp=-1;
		for(int i=0;i<exWords.length;i++){
			if(str.equals(exWords[i]))
				return i;
		}
		return temp;
	}

	/*得到可编号化的集合*/
	private static String[] getExWords(String[][] twos) {
		ArrayList<String> temp=new ArrayList<String>(10);
		for(String[] words:twos)
			for(String word:words)
				if(!temp.contains(word))
					temp.add(word);
		String[] exWords=new String[temp.size()];
		for(int i=0;i<temp.size();i++)
			exWords[i]=temp.get(i);
		return exWords;
	}

	/*打印结果集*/
	private static void printResult(String[] list) {
		for(int i=0;i<list.length;i++)
			System.out.println("Case #"+(i+1)+":"+list[i]);
		
	}

	/*有循环体参与的句子中词语处理*/
	private static void swap(String[] words, int j, List<List<Integer>> listC, int n,String[] exWords) {
		String temp=words[j];
		int intTemp=getIndex(temp,exWords);
		for(List<Integer> list:listC){
			if(list.contains(intTemp)){
				int index=list.indexOf(intTemp);
				int size=list.size();
				int step=n-1;
				words[j]=exWords[list.get((index+step)%size)];
				return;
			}
		}
	}

	/*有传递体参与的句子中词语处理*/
	private static void swap(String[] words, int j, List<List<Integer>> listC,List<List<Integer>> listT,
			int n, String[] exWords) {
		String temp=words[j];
		int intTemp=getIndex(temp,exWords);
		for(List<Integer> list:listT){
			if(list.contains(intTemp)){
				int index=list.indexOf(intTemp);
				int size=list.size();
				int step=n-1;
				if(index+step<size-1)
					words[j]=exWords[list.get(index+step)];
				else{
					int x=size-2-index;
					if(list.get(size-1)==FLAG){
						words[j]=exWords[list.get(size-2)];
						swap(words,j,listC,n-x,exWords);
					}else{
						words[j]=exWords[list.get(size-1)];
					}
				}
				return;
			}
		}
	}

	/* 为处理集合赋值*/
	private static void handleWords(List<List<Integer>> circulate,
			List<List<Integer>> transmit, int[][] twos, String[] exWords) {
		int[] keys=get(twos,0);
		int[] values=get(twos,1);
		for(int i=0;i<twos.length;i++){
			/* 对一个处理链条的第一个词进行处理*/
			if(disContains(twos[i][0],values))
				handleHead(twos[i][0],twos,circulate,transmit,values);
			else{
				if(test(twos[i][0],twos,keys,values)&&noCir(circulate,twos[i][0]))
					handleHead(twos[i][0],twos,circulate,transmit,values);
			}
		}
	}

	private static boolean noCir(List<List<Integer>> lists, int k) {
		for(List<Integer> list:lists){
			if(list.contains(k))
				return false;
		}
		return true;
	}

	private static boolean test(int k, int[][] twos,int[] keys, int[] values) {
		int x=-10;
		int temp=k;
		int value=getValue(temp,twos);
		if(value==-1)
			return false;
		while((!disContains(value,keys))&&(x<twos.length)){
			value=getValue(temp,twos);
			x++;
		}
		if(x==twos.length)
			return true;
		return false;
	}

	/*词组不包含某词编号*/
	private static boolean disContains(int k, int[] values) {
		for(int i=0;i<values.length;i++){
			if(k==values[i])
				return false;
		}
		return true;
	}

	/*得到变换词对的某一集合*/
	private static int[] get(int[][] twos, int k) {
		ArrayList<Integer> temp=new ArrayList<Integer>(11);
		for(int i=0;i<twos.length;i++){
			if(!temp.contains(twos[i][k]))
				temp.add(twos[i][k]);
		}
		int[] intTemp=new int[temp.size()];
		for(int i=0;i<intTemp.length;i++)
			intTemp[i]=temp.get(i);
		return intTemp;
	}

	/*对于某一个处理链条的词进行分类*/
	private static void handleHead(int head, int[][] two,
			List<List<Integer>> circulate,
			List<List<Integer>> transmit, int[] values) {
		List<Integer> temp=new ArrayList<Integer>(11);
		temp.add(head);
		int value=getValue(head,two);
		while((!temp.contains(value))&&(value!=-1)){
			temp.add(value);
			value=getValue(value,two);
		}
		if(value==-1){
			transmit.add(temp);
		}else{
			handle(circulate,transmit,temp,value);
		}
	}

	/* 对于某一个词,得到其变换后的词*/
	private static int getValue(int head, int[][] two) {
		int temp=-1;
		for(int i=0;i<two.length;i++){
			if(head==two[i][0])
				temp=two[i][1];
		}
		return temp;
	}

	/*处理包含循环的集合链条*/
	private static void handle(List<List<Integer>> circulate, List<List<Integer>> transmit,
			List<Integer> temp,int value) {
		if(temp.indexOf(value)==0){
			circulate.add(temp);
		}else{
			handleCir(circulate,value,temp);
			temp.add(FLAG);
			transmit.add(temp);
		}
	}

	/*处理单纯循环体*/
	private static void handleCir(List<List<Integer>> circulate, int value,
			List<Integer> temp) {
		if(noCir(circulate,value)){
			return;
		}
		int index=temp.indexOf(value);
		List<Integer> list=new ArrayList<Integer>(11);
		for(int i=index;i<temp.size();i++){
			list.add(temp.get(i));
		}
		circulate.add(list);
	}
}


这是通过了小数据测试的,大数据是否能通过就不知道了。

——20130409


PS:

今天早晨数据出来了,这道题的大数据测试是三个题中唯一的一个AC。在意料之外,以为要是能AC一题也是长方形那个题。但,结果也不错。

——20130409


相关文章
|
21天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
5天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
20天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
19天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
12天前
|
Java API 数据库
Java 反射机制:动态编程的 “魔法钥匙”
Java反射机制是允许程序在运行时访问类、方法和字段信息的强大工具,被誉为动态编程的“魔法钥匙”。通过反射,开发者可以创建更加灵活、可扩展的应用程序。
32 0
时间轮-Java实现篇
在前面的文章《[时间轮-理论篇](https://developer.aliyun.com/article/910513)》讲了时间轮的一些理论知识,然后根据理论知识。我们自己来实现一个简单的时间轮。
|
28天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
12天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
6天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
11天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
42 1