`
qingtangpaomian
  • 浏览: 39100 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

USACO - 3.1.5 - Contact

 
阅读更多

 


原创文章转载请注明出处

摘要:二叉树的应用 ,三星

一. 题目翻译

1. 描述:
奶牛们开始对用射电望远镜扫描牧场外的宇宙感兴趣。最近,他们注意到了一种非常奇怪的脉冲调制微波从星系的中央发射出来。他们希望知道电波是否是被某些地外生命发射出来的,还是仅仅是普通的的星星发出的。
帮助奶牛们用一个能够分析他们在文件中记下的记录的工具来找到真相。他们在寻找长度在A到B之间(含)在每天的数据文件中重复得最多的比特序列 (1 <= A <= B <= 12)。他们在找那些重复得最多的比特序列。一个输入限制告诉你应输出多少频率最多的序列。
符合的序列可能会重叠,并且至少出现一次的序列会被计数。

2. 格式:

          INPUT FORMAT:

          第一行: 三个用空格分隔的整数: A, B, N; (1 <= N < 50)
          第二行及以后: 一个最多200,000字符的序列,全是0或1; 每行字符数不大于80。

          OUTPUT FORMAT:

          输出N个频率最高的序列(按照频率由高到低的次序)。由短到长排列频率相同的这些序列,如果长短相同,按二进制大小排列。如果出现的序列个数小于N,输出存在的序列。
          对于每个存在的频率,先输出单独包含该频率的一行,再输出以空格分隔的这些频率。每行六个(除非少于六个剩下)。

3. SAMPLE:
          SAMPLE INPUT:
2 4 10
01010010010001000111101100001010011001111000010010011110010000000
在样例里,序列100出现了12次,而序列1000出现了5次。次数最多的序列是00,出现了23次。
          SAMPLE OUTPUT:
23
00
15
01 10
12
100
11
11 000 001
10
010
8
0100
7
0010 1001
6
111 0000
5
011 110 1000
4
0001 0011 1100


二.  题解

1. 题意理解(将问题分析清楚,大致用什么思路):
         看到这道题目其实应当可以想到一个最简单方法就是用一个hash表将所有出现过的字符串存储起来,如果查hash表里面有则将原来的值++,如果没有则在hash表中增加一个key为字符串,value为0的新节点(在网上看到有大牛用java写这种方法也过了,大家有兴趣的话可以尝试一下)。
          这道题目还有一个非常巧妙的解法,数据结构是一个满二叉树(大家可以先自己思考下为什么)。
(囧, 插图很复杂啊。。。就是一颗二叉树,类似于霍夫曼编码的二叉树)
参考上面的这幅图,大家可以看到。00字符串出现的次数=000字符串出现的次数+001字符串出现的次数。那么对应到我们的这一道题目,我们求出所有长度为B(题目中要求的最大长度)的字符串出现的次数就可以向上推出任意的长度大于等于A(最小长度)的字符串出现次数。 那么现在又出现了一个新的问题,就是如何表示这颗树 ? 常用的树有两种表示方法:1. 用链表,左孩子,右孩子;2.用一个数组,这道题目我们使用数组的表示方法,数中节点与数组下标的对应我们可以参考满二叉树的编码(满二叉树中节点i的左孩子是2*i+1,右孩子是2*i+2)。


 

2. 具体实现(具体实现过程中出现的问题):
在具体实现的过程中,出现了如下的一个问题。就是对于题目中给出的字符串最后的A位,由于他们之后没有节点了,所以在数中也无法递推产生他们的出现次数。
         举个例子:程序sample当中01010010010001000111101100001010011001111000010010011110010000000这个串的最后三位000,由于我们是通过长度为4的字符串递推产生长度小于4的字符串出现频率,那么000我们会少计算1次,00会少计算2次,0会少计算3次。
       所以在程序实现的过程中,除了需要将所有长度为A的字符串的出现次数统计出来外,还需要将字符串最后A-1当中各种长度的字符串统计一次。有了这个以后我们需要修改原来的方程如下 父节点出现的次数=左孩子出现的次数+右孩子出现的次数+父节点之前出现的次数(在输入字符串的后A位中)。
        算法的实现请参考代码注释。

4. 启示:
          非常有意思的一道题目,对于这类统计字符出现次数的题,这一道很不错,大家可以积累、参考。

三.  代码

/*
ID:fightin1
LANG:JAVA
TASK:contact
*/
package session_3_1_5;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

public class contact {

	public static void main(String[] args) throws Exception {

		PrintWriter pw = new PrintWriter(System.out);
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
//		BufferedReader br = new BufferedReader(new FileReader("contact.in"));
//		PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
//		"contact.out")));
		
		StringTokenizer tokens = new StringTokenizer(br.readLine());
		
		int A = Integer.parseInt(tokens.nextToken());
		int B = Integer.parseInt(tokens.nextToken());
		int N = Integer.parseInt(tokens.nextToken());

		int[] tree = new int[16384];//存储完全二叉树的数组,由于题目当中要求最大的子串长度为12,所以树的最大深度应当为12层。但是在题目当中字符串可以以1开始,所以我们加入一层。数的深度为13,节点总和为2^14
		ArrayList<Node> al = new ArrayList<Node>();//存储结果

		StringBuilder sb = new StringBuilder();
		String readLine = br.readLine();
		while(readLine!=null){
			sb.append(readLine);
			readLine = br.readLine();
		}

		for (int i=0;i+B<=sb.length();i++){//将长度为B的所有字符串出现次数存储在树中
			String line = sb.substring(i, i+B);
			add(line ,tree ,B);
		}
		
		for (int i=B-1;i>=1;i--){//统计给定字符串最后B-1位各长度字符串出现的次数
			for (int j=sb.length()-i;j>=0&&i+j<=sb.length();j++){
				String line = sb.substring(j, j+i);
				add(line, tree, i);
			}
		}
		
		caculate(tree , A, B, al);//根据解题报告当中给出的公式推算各种长度字符串出现的频率
		print(al, pw ,N);
	}

	//更新line描述字符串出现次数
	public static void add(String line ,int[] tree ,int B) {
		int index = 0;
		for (int i=0;i<B;i++){
			char temp = line.charAt(i);
			if (temp=='0'){
				index = 2*index + 1;
			} else if (temp=='1'){
				index = 2*index + 2;
			}
		}
		tree[index]++;
	}
	
	//根据解题报告当中给出的公式结算各长度字符串出现的频率
	public static void caculate(int[] tree ,int A ,int B ,ArrayList<Node> al) {
		int start = 0;
		int end = 0;
		for (int i=0;i<A;i++){
			start = 2*start + 1;
		}
		for (int i=0;i<B;i++){
			end = 2 * end + 2; 
		}
		for (int i=end;i>=start;i--){
			tree[i] = tree[i] + tree[2*i+1] + tree[2*i+2];//当前节点表示的字符串出现次数=左孩子+右孩子+字符串后B-1位中的次数
			if (tree[i]!=0)
				al.add(new Node(i,tree[i]));//如果字符串出现次数大于1,则加入结果集中排序,结果用Node类封装。
		}
		Collections.sort(al);
	}
	
	//输出,我写的有点复杂,大家掌握思路以后可以自己写个。
	public static void print(ArrayList<Node> al ,PrintWriter pw ,int N){
		int tempTimes = 0;
		int tempCnt = 1;
		int count = 0;
		StringBuilder output = new StringBuilder();
		for (int i=0;i<al.size();i++){
			Node node = al.get(i);
			if (i==0){
				tempTimes = node.times;
				tempCnt =1 ;
				output.append(tempTimes+"\n");
				output.append(node.binary+" ");
			} else {
				if (node.times == tempTimes){
					if (tempCnt <= 5){
						output.append(node.binary+" ");
						tempCnt++;
					} else {
						output.deleteCharAt(output.length()-1);
						output.append("\n");
						output.append(node.binary+" ");
						tempCnt = 1;
					}
				} else {
					output.deleteCharAt(output.length()-1);
					count ++;
					if (count==N){
						break;
					} else {
						output.append("\n");
						output.append(node.times+"\n");
						output.append(node.binary+" ");
						tempCnt = 1;
						tempTimes = node.times;
					}
				}
			}		
		}
		if (output.charAt(output.length()-1)==' '){
			output.deleteCharAt(output.length()-1);
		}
		pw.println(output);
		pw.close();
	}
}

//记录结果用的,大家可以不用参考
class Node implements Comparable<Node>{
	int posistion;
	int times;
	String binary;
	int value;
	int length;
	
	public Node(int position ,int times) {
		this.posistion = position;
		this.times = times;
		binary = getBinary();
		value = getValue();
	}
	
	private String getBinary(){
		StringBuilder result = new StringBuilder("");
		int temp = posistion;
		while (temp!=0){
			if (temp%2 == 1){
				result.append(0);
			} else {
				result.append(1);
			}
			length++;
			temp = (temp-1)/2;
		}
		result.reverse();
		return result.toString();
	}
	
	private int getValue(){
		int result = 0;
		for (int i=0;i<binary.length();i++){
			char temp = binary.charAt(i);
			if (temp == '1'){
				result = 2*result + 1;
			} else {
				result = 2*result;
			}
		}
		return result;
	}
	
	@Override
	public int compareTo(Node o) {
		if (times>o.times){
			return -1;
		} else if (times == o.times){
			if (length > o.length){
				return 1;
			} else if (length == o.length){
				if (value > o.value){
					return 1;
				} else if (value == o.value){
					return 0;
				} else {
					return -1;
				}
			} else 
				return -1;
			
		} else {
			return 1;
		}
	}
}


分享到:
评论

相关推荐

    USACO-Bessie-Come-Home.zip_Home Home

    【标题】USACO-Bessie-Come-Home.zip_Home Home 【正文】 这个压缩包文件中的内容是关于USACO(美国计算机奥林匹克)竞赛中一个名为"Bessie Come Home"的问题的C++解决方案。USACO是一个针对高中生的在线编程竞赛...

    USACO-beads.rar_usaco bea

    【标题】USACO-beads.rar_usaco bea 【正文】 USACO(美国计算机奥林匹克竞赛)是一项针对中学生举办的编程比赛,旨在培养和选拔未来的计算机科学家。在这个特定的题目"beads"中,我们需要解决的问题是找到最长的...

    USACO-Magic-Squares.zip_magic

    《USACO魔法方阵:C++编程解析》 USACO(美国计算机奥林匹克)是一项旨在培养高中生计算机科学技能的竞赛。在这个问题中,我们关注的是“Magic Squares”,这是一个经典的数学概念,与C++编程相结合,构成了一个...

    USACO-Chapter2.rar_beginners

    "USACO-Chapter2.rar_beginners" 是针对USACO第二章内容的压缩包,特别适合编程新手入门。 在USACO的第二章,主要涉及基础的算法和数据结构,这对于构建扎实的编程基础至关重要。让我们逐一解析这个压缩包中的四个...

    USACO-Chapter1.rar_it_usaco

    《USACO入门指南——第一章解析》 USACO,全称USA Computing Olympiad,是美国计算机奥林匹克竞赛,旨在培养中学生在算法和编程方面的技能。对于初学者来说,USACO提供了很好的学习路径和挑战。本文将针对USACO的第...

    usaco-1.rar_barn1

    【标题】"usaco-1.rar_barn1" 涉及的是USACO(美国计算机奥林匹克)竞赛中的一道编程题目,名为“Barn1”。USACO是一个旨在提升中学生计算机科学技能的比赛,主要关注算法和编程。在本题中,参赛者需要解决与农业或...

    USACO-Greedy-Gift-Givers.rar_greedy gift givers

    USACO(USA Computing Olympiad)是一项面向美国高中生的在线编程竞赛,旨在培养参赛者的算法设计和编程技能。在"Greedy Gift Givers"这个题目中,我们面对的是一个贪心算法的应用问题。贪心算法是一种解决问题的...

    USACO2001-2007历年月赛测试数据+题目+题解打包全

    资源包包括USACO 2001-2007年月赛的测试数据;usaco月赛十年题典(2000-2009),usaco月赛2002-2008题解。单独下载需资源分30分以上。为了方便编程爱好者,我这边统一下载打包。欢迎下载。

    USACO-Training-Website:我的USACO培训网站解决方案

    这个名为"USACO-Training-Website:我的USACO培训网站解决方案"的压缩包文件,显然包含了作者对USACO训练网站上部分或所有章节的练习题目的解答。这些解答可能以源代码的形式存在,每个文件顶部可能带有详细的USACO...

    USACO-Practice:USACO 实践

    这个"USACO-Practice"压缩包文件显然是为了帮助参赛者或者对算法有兴趣的学生准备的实践资源。以下我们将深入探讨USACO竞赛的相关知识点以及可能在压缩包中包含的编程内容。 1. **基础算法**:USACO竞赛通常会涉及...

    USACO-Training-Pages:美国计算机奥林匹克训练页

    在这个“USACO-Training-Pages”压缩包中,我们可以期待找到与USACO竞赛相关的各种资料,尤其是针对Java语言的学习材料。Java作为一种广泛应用于计算机科学领域的面向对象的编程语言,因其强大的跨平台能力和简洁的...

    Notes-USACO-2021-弹簧

    本压缩包“Notes-USACO-2021-Spring”中的笔记主要聚焦于2021年春季训练营和比赛的知识点,对于想要深入学习算法和提升编程能力的爱好者来说,具有极高的学习价值。 笔记内容可能包括但不限于以下几个方面: 1. **...

    USACO2001-2007月赛全集

    这是USACO2001-2007月赛全集。 usaco是美国中学生的官方竞赛网站。是美国著名在线题库,专门为信息学竞赛选手准备。推荐直接阅读英语原文,既准确可靠又可提高英语水平。做题方式模拟正式比赛,采用标准测评机、文件...

    C-Usaco-Work:Usaco在C中的工作

    "C-Usaco-Work"指的是一个针对Usaco(美国计算机奥林匹克)教程的项目,这个项目专门用于帮助参赛者学习如何在C语言环境下进行竞赛编程。Usaco是一项面向高中生的国际性计算机科学竞赛,旨在提高参赛者的算法设计、...

    usaco 2010-2011

    ### USACO 2010-2011 季度竞赛概览与关键信息 #### 一、概述 美国计算机奥林匹克(USACO)是面向全球中学生的计算机科学竞赛,旨在发掘并培养计算机科学领域的年轻人才。USACO 2010-2011 季度竞赛于 2010 年 11 月...

    usaco-java-gold

    在这个“usaco-java-gold”主题中,我们将深入探讨Java在USACO黄金级别比赛中的应用,以及如何解决相关问题。 一、Java语言基础 1. 类与对象:Java是一种面向对象的语言,理解和熟练运用类和对象是解决USACO问题的...

    USACO-Cpp

    【USACO-Cpp】是针对USACO(美国计算机奥林匹克竞赛)的C++编程教程资源,主要面向参赛者提供C++语言的学习材料,帮助他们在比赛中解决算法和数据结构问题。USACO是一项旨在提升高中生计算机科学技能的比赛,强调...

    USACO-TurtleCamera:该存储库包含我对USACO问题的所有解决方案

    USACO-TurtleCamera 该存储库包含我对USACO问题的所有解决方案。 CSE 199工作区目录将是我用来帮助开发USACO课程的主要目录。

    USACO题解+程序

    我的USACO题解和程序

    USACO-Guide

    《USACO-Guide》是面向参赛者,特别是那些对美国计算机奥林匹克竞赛(USACO)感兴趣的编程爱好者的一份重要资源。USACO是美国一项旨在提升高中生编程技能的竞赛,它涵盖了算法、数据结构以及问题解决等多个方面的...

Global site tag (gtag.js) - Google Analytics