P1042 [NOIP2003 普及组] 乒乓球 Java版最简单题解!

news2024/9/27 2:44:33

为什么说最简单,因为本人就是一个算法小白,只学过一点数据结构,打算备战蓝桥杯的,网上说备战蓝桥杯就去刷洛谷,早有听闻洛谷很难,今天一看算是真的被打醒了,对于小白是真的太难了。(;´༎ຶД༎ຶ`)

解题之前,先了解一下Java快速输入输出工具。

Java(最)快速输入输出工具:

首先,听说Java输入输出有快速的方法,于是乎做这道题,在网上搜了一些快速输入输出的方法,我觉得这个东西就是理解为模板吧,就类似于Scanner,一开始学的时候也没问它到底什么原理(说实话现在也还不知道),清楚怎么用就行。同样道理,(最)快速输入输出也是,知道他怎么用就行。下面介绍Java的(最)​​​​​​​快速输入StreamTokenizer  以及快速输出:PrintWriter 。

实例化以及调用模板:

public class Main {

	// (最)快速输入输出模板
	static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));// 输入,相当于scanner.xxx
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));// 输出,相当于System.out.xxx
	// (最)快速输入输出模板

	public static void main(String[] args) throws IOException {
		// ....代码
	}
}

两个东西有点臭长的感觉,但是仔细一看,其实他们实例化的构造函数参数还是有相同之处的,都用了缓冲流,如果想要了解更多,这里也转载一篇大佬的文章,讲解的很详细,它里面还讲了一种不同于普通的Scanner的快速输入法。

下面再列举一个测试样例,帮助理解使用这两个工具。用之前,有一些注意事项:


1. 只能输入数字和普通字符(例如输入:"~!@#$%^&*()_+{}:<>?"会用null代替)
2. 每次调用in.val或者in.sval之前,必须先调用in.nextToken();
3.用PrintWriter打印内容(即调用out.print()/out.println()之后)必须在后面调用out.close(),否则不会打印任何内容
        

测试样例代码:

package Test;

import java.io.*;

public class Main {
	// (最)快速输入输出模板
	static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));// 输入,相当于scanner.xxx
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));// 输出,相当于System.out.xxx
	
	public static void main(String[] args) throws IOException {

		// 输入数字类型:
		in.nextToken();
		int a = (int) in.nval;		// 由于in.nval返回的是double类型,所以在输入数字的时候还要强制类型转换一下
		in.nextToken();
		int b = (int) in.nval;
		out.print(a + b);	
		// 输入字符串类型:
		String str = "";
		while (in.nextToken() != StreamTokenizer.TT_EOL) {
            str = in.sval;		// 这个循环可以不断的将字符串类型测试数据输入到str中(每一次循环以换行分割)
			/** 但是这样在自己eclipse上可能不太好测试,因为不能停止循环,只能控制次数的用下面这样:
				in.nextToken();
				str += in.sval;
				in.nextToken();
				str += in.sval;
				...
			*/
		}
		out.close();
	}
}

其实StreamTokenizer 很简单,就只能输入数字和字符串,数字的输入默认是double类型,所以转换其他数字类型直接强制类型转换一下就行。但如果想字符串类型变成字符型或者其他,那就涉及比较多方法了,常用的有像:String类的toCharArray();还有字符串分割split();,我的一篇文章中总结过String转其他类型的方法。

还有,为什么敢说最快呢,下面是我用普通的Scanner和System.out.print法输入输出 做洛谷最简单的一道P1001 A+B Problem,和用StreamTokenizer+PrintWriter做的运行时长对比:

普通方法:

 快速方法:

题解:

为什么会想到快速输入输出工具呢?其实没什么特别的帮助,只是想让自己代码更快点,据说比赛的时候最好用快读快输。

所以抛开快读和块输的话,我做这题就是简单的用两次相同的循环,分开打印两种不同分制的结果,关键利用了for循环的特性,在第一层for循环中 是控制每场的开始位置, j 就控制每一局内部的移动,有点类似双指针法的思想。

代码1.0:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class LQBDay3 {
	static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	public static void main(String[] args) throws IOException {
		
		int w11 = 0;	// 11分制华华获胜次数
		int l11 = 0;	// 11分制华华对手获胜次数
		int w21 = 0;	// 21分制华华获胜次数
		int l21 = 0;	// 21分制华华对手获胜次数
		char[] ch = null;
		String str = "";
		in.nextToken();
		str += in.sval;		// 先加入第一行对局情况
		while(true) {		// 再循环加入对局情况
			if(str.indexOf('E') == -1) {// 如果这一行不存在E,则继续输入
				in.nextToken();
				str += in.sval;
			}else {						// 否则,退出输入
				break;	
			}
		}
		// 用一个字符数组存储全部输入的对局情况,上面的str是不包括'\n'(回车)的
		ch = str.toCharArray();		
		for(int i = 0; i < ch.length; i+= 11) {	// i以11个为一组
			int j = i;
			w11 = 0;
			l11 = 0;
			// 下面循环是判断一局对战,华华和对手胜负情况的
			while(ch[j] != 'E') {				// 显然,退出循环的条件是遇到E了
				
				if(ch[j] == 'W') {
					w11++;
				}else if(ch[j] == 'L') {
					l11++;
				}
				// 判断一场比赛结束的条件是否满足
				if(w11 + l11 >= 11) {			// 由于上面for循环中,i我默认控制的是自增11,但是当两人比赛超过了11场,需要让这场比赛的区间扩大,下面有可能需要让i++
					
					if(Math.abs(w11 - l11) >= 2 && (w11 >= 11 || l11 >= 11)) {	// 差值大于2则说明这局比赛已分胜负,并且
						break;
					}else {		// 此时和已经大于11了,但是还是没分出胜负,例如:5:6,显然这时候还没分出胜负,
								// 这时为了让下一场比赛的i在正确的位置,需要让i++,理解为i是控制一场比赛的次数的区间长度
						i++;
					}
				}
				// j移动表示一局比赛的下一个回合
				j++;
			}
			out.println(w11 + ":" + l11);
		}
		
		out.println();
		for(int i = 0; i < ch.length; i+= 21) {	// i以11个为一组
			int j = i;
			w21 = 0;
			l21 = 0;
			while(ch[j] != 'E') {
				if(ch[j] == 'W') {
					w21++;
				}else if(ch[j] == 'L') {
					l21++;
				}
				// 判断退出一场比赛的条件是否满足
				if(w21 + l21 >= 21) {		
					if(Math.abs(w21 - l21) >= 2&& (w21 >= 21 || l21 >= 21)) {	// 差值大于2则说明这局比赛已分胜负
						break;
					}else {		// 此时和已经大于11了,但是还是没分出胜负,例如:5:6,显然这时候还没分出胜负,
								// 这时为了让下一场比赛的i在正确的位置,这时只需要让i++
						i++;
					}
				}
				j++;
			}
			out.println(w21 + ":" + l21);
		}
		out.close();
	}

}

 显然,两个比赛计算得分情况的代码重复了,一位优秀的程序猿应该要懂得把类似的方法抽象出来,下面是优化之后的代码:

代码2.0:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
	static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	public static void main(String[] args) throws IOException {
		
		char[] ch = null;
		String str = "";
		in.nextToken();
		str += in.sval;		// 先加入第一行对局情况
		while(true) {		// 再循环加入对局情况
			if(str.indexOf('E') == -1) {// 如果这一行不存在E,则继续输入
				in.nextToken();
				str += in.sval;
			}else {						// 否则,退出输入
				break;	
			}
		}
		// 用一个字符数组存储全部输入的对局情况,上面的str是不包括'\n'(回车)的
		ch = str.toCharArray();		
		MatchSituation(ch, 11);		// 打印11分制情况
		out.println();				// 空一行
		MatchSituation(ch, 21);		// 打印21分制情况
		out.close();
	}
	/**
	 * 
	 * @param ch(比赛情况)
	 * @param system(11分制/21分制)
	 */
	public static void MatchSituation(char[] ch, int system) {
		for(int i = 0; i < ch.length; i+= system) {	// i以system(11/21分制)个为一组
			int j = i;
			int win = 0;		// 华华获胜的场数
			int lose = 0;		// 华华失败的场数
			// 下面循环是判断一局对战,华华和对手胜负情况的
			while(ch[j] != 'E') {				// 显然,退出循环的条件是遇到E了
				
				if(ch[j] == 'W') {
					win++;
				}else if(ch[j] == 'L') {
					lose++;
				}
				// 判断一场比赛结束的条件是否满足
				if(win + lose >= system) {			// 由于上面for循环中,i我默认控制的是自增11/21,但是当两人比赛超过了11/21场,需要让这场比赛的区间扩大,下面有可能需要让i++
					
					if(Math.abs(win - lose) >= 2 && (win >= system || lose >= system)) {	// 差值大于2则说明这局比赛已分胜负,并且
						break;
					}else {		// 此时和已经大于11/21了,但是还是没分出胜负,例如11分制中:5:6,显然这时候还没分出胜负,
								// 这时为了让下一场比赛的i在正确的位置,需要让i++,理解为i是控制一场比赛的次数的区间长度
						i++;
					}
				}
				// j移动表示一局比赛的下一个回合
				j++;
			}
			out.println(win + ":" + lose);
		}
	}
}

运行结果图:

 我认为上面的题解应该比较好懂了,小白刷题第一天,加油加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1414538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Idea中使用git查看历史版本

idea查git历史 背景查看步骤总结 背景 有好几次同事到我电脑用idea查看git管理的历史记录&#xff0c;每次都说我的idea看不了历史版本&#xff0c;叫我到他电脑上去看&#xff0c;很晕&#xff0c;为什么,原来是我自己把显示历史文件的视图覆盖了&#xff0c;下面我们来一起学…

Python open函数

在Python编程中&#xff0c;open()函数是一个重要的文件操作函数&#xff0c;用于打开文件并进行读取、写入、追加等操作。本文将深入探讨open()函数的用法、语法、文件模式、示例代码&#xff0c;并探讨其在实际编程中的应用场景。 什么是open()函数&#xff1f; open()函数…

【阻塞队列】阻塞队列的模拟实现及在生产者和消费者模型上的应用

文章目录 &#x1f4c4;前言一. 阻塞队列初了解&#x1f346;1. 什么是阻塞队列&#xff1f;&#x1f345;2. 为什么使用阻塞队列&#xff1f;&#x1f966;3. Java标准库中阻塞队列的实现 二. 阻塞队列的模拟实现&#x1f35a;1. 实现普通队列&#x1f365;2. 实现队列的阻塞功…

Python.五.文件

1.文件读取的操作 1.文件的打开 open(name,mode,encoding) name:是要打开目标文件名的字符串&#xff0c;可以包含文件所在的具体路径 mode:设置打开文件的模式&#xff1a;只读 r 、写入 w 、追加 a encoding&#xff1a;编码格式 UTF-8 fopen("C:/test.txt"…

XSS_Labs靶场通关笔记

每一关的方法不唯一&#xff1b;可以结合源码进行分析后构造payload&#xff1b; 通关技巧&#xff08;四步&#xff09;&#xff1a; 1.输入内容看源码变化&#xff1b; 2.找到内容插入点&#xff1b; 3.测试是否有过滤&#xff1b; 4.构造payload绕过 第一关 构造paylo…

怎么获取二维码的链接?二维码转链接只需3步

怎么从二维码中提取内容呢&#xff1f;现在很多内容都会用二维码方式来存储&#xff0c;但是有些场景下二维码是无法使用的时候&#xff0c;想要查看二维码中的内容&#xff0c;就需要分解二维码成链接后使用。那么二维码分解成链接具体该怎么做呢&#xff1f;今天就将在线二维…

Hammer.js中文教程

一、什么是hammer.js hammerJS是一个开源的&#xff0c;轻量级的触屏设备javascript手势库&#xff0c;它可以在不需要依赖其他东西的情况下识别触摸&#xff0c;鼠标事件。允许同时监听多个手势、自定义识别器&#xff0c;也可以识别滑动方向。 优点&#xff1a; 为移动端网…

[已解决]504 Gateway Time-out 网关超时

文章目录 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时思路解决 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时 思路 网上的常规思路是修改nginx配置文件,增加请求执行时间,试过没有用 keepalive_timeout 600; fastcgi_con…

一文读懂: AIGC基本原理及应用领域

AIGC是利用人工智能技术来生成内容的一种新型技术。随着人工智能技术的不断发展&#xff0c;AIGC技术也得到了越来越广泛的应用。未来&#xff0c;AIGC技术将会对我们的生活和工作产生巨大的影响。 一、AIGC技术的基本原理 AIGC技术的基本原理是利用人工智能技术中…

JAVA学习笔记三

1.java执行流程分析 2.什么是编译 javac Hello.java 1.有了java源文件&#xff0c;通过编译器将其编译成JVM可以识别的字节码文件 2.在该源文件目录下&#xff0c;通过javac编译工具对Hello.java文件进行编译 3.如果程序没有错误&#xff0c;没有任何提示&#xff0c;但在…

[数据结构]-哈希

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标&…

LabVIEW准分子激光器控制系统

LabVIEW准分子激光器控制系统是为了实现准分子激光光源在工业、医疗和科研领域的应用集成及其功能的扩展。系统由PC端和激光器端两部分构成&#xff0c;通过光隔离的RS232通讯连接&#xff0c;以实现稳定可靠的控制与通信。 系统主要由微控制单元&#xff08;MCU&#xff09;主…

程序员的你,是不是又被催婚了

程序员作为社会中一个较为特殊的群体&#xff0c;由于工作特性&#xff08;如长时间对着电脑、工作节奏较快、加班相对频繁等&#xff09;以及职业发展需要投入大量时间和精力&#xff0c;有时可能会面临较晚结婚的问题。这也导致了在某些情况下&#xff0c;他们可能被家人或朋…

C#使用TimeSpan对象获取时间间隔

目录 一、TimeSpan基础知识 二、实例 一、TimeSpan基础知识 使用TimeSpan对象可以方便地获取两个时间段的间隔。两个时间信息相减后会得到一个TimeSpan对象&#xff0c;该TimeSpan对象代表时间间隔&#xff0c;可以通过TimeSpan对象的Days、Hours、Minutes、Seconds、Millise…

腾讯云幻兽帕鲁专有服务器配置价格表,4核16G、8核32G

幻兽帕鲁服务器配置CPU内存多大合适&#xff1f;如何选择&#xff1f;最低4核8G起步&#xff0c;4核16G是官方推荐配置&#xff0c;最好是4核32G配置。阿腾云atengyun.com分享幻兽帕鲁Palworld服务器CPU内存配置及租用费用&#xff0c;如下图&#xff0c;Palworld官方推荐服务器…

利用Django搭建python web项目(简单登录)

1.概述 目前市面上web项目大多数是由java语言开发&#xff08;结合spring框架&#xff09;&#xff0c;但这并不意味着只有java语言能够开发web项目&#xff0c;python语言、go语言同样可以做到。本文将利用Django框架&#xff08;由python语言开发的web框架&#xff09;来搭建…

09. Springboot集成sse服务端推流

目录 1、前言 2、什么是SSE 2.1、技术原理 2.2、SSE和WebSocket 2.2.1、SSE (Server-Sent Events) 2.2.2、WebSocket 2.2.3、选择 SSE 还是 WebSocket&#xff1f; 3、Springboot快速集成 3.1、添加依赖 3.2、创建SSE控制器 3.2.1、SSEmitter创建实例 3.2.2、SSEmi…

esp32 操作DS1307时钟芯片

电气参数摘要 有VCC供电&#xff0c;IIC活动状态是1.5mA&#xff0c;待机状态200μA&#xff0c;电池电流5nA(MAX50nA&#xff09;无VCC供电的时候&#xff0c;电池电流&#xff0c;300nA&#xff08;时钟运行&#xff09;&#xff0c;10nA&#xff08;时钟停止&#xff09;供…

ASP.NET Core 7 Web 使用Session

ASP.NET Core 好像不能像20年前那样直接使用Session函数&#xff0c;我使用如下方法 1、在NuGet安装以下2个包 2、在Program.cs注册 //注册Session builder.Services.AddSession(options > {options.IdleTimeout TimeSpan.FromMinutes(60);options.Cookie.HttpOnly fals…

大小端(C语言)

一、什么是大小端&#xff1a; 1.大端(Big-Endian):高地址存放低位 2.小端(Little-Endian):高地址存放高位 例如&#xff1a;0x11223344在内存中存储 大小端影响了什么&#xff1f; 当基本数据类型占用字节数超过了1字节后&#xff0c;大小端决定了数据按照什么顺序存储在…