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

2024-01-27 20:36

本文主要是介绍P1042 [NOIP2003 普及组] 乒乓球 Java版最简单题解!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

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

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

实例化以及调用模板:

public class Main {// (最)快速输入输出模板static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));// 输入,相当于scanner.xxxstatic 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.xxxstatic PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));// 输出,相当于System.out.xxxpublic 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);}}
}

运行结果图:

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

这篇关于P1042 [NOIP2003 普及组] 乒乓球 Java版最简单题解!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/651415

相关文章

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

Java 方法重载Overload常见误区及注意事项

《Java方法重载Overload常见误区及注意事项》Java方法重载允许同一类中同名方法通过参数类型、数量、顺序差异实现功能扩展,提升代码灵活性,核心条件为参数列表不同,不涉及返回类型、访问修饰符... 目录Java 方法重载(Overload)详解一、方法重载的核心条件二、构成方法重载的具体情况三、不构

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys