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


相关文章
|
3天前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
7天前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
34 12
|
3天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
38 2
|
20天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
20天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
43 3
|
IDE 小程序 前端开发
详细解读java的俄罗斯方块游戏的源代码--【课程设计】
详细解读java的俄罗斯方块游戏的源代码--【课程设计】
|
Java 定位技术 开发者
基于Java的俄罗斯方块游戏
基于Java的俄罗斯方块游戏
|
Java 定位技术
Java---俄罗斯方块小游戏
去年就已经学了这个技术了,一直没去写,现在抽个时间写了个俄罗斯方块游戏。 只有简单的新游戏,暂停,继续,积分功能。简单的实现了俄罗斯的经典功能。 不介绍了,有兴趣的自己运行一下,后面贴出了图片。
1025 0
|
1天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者