1. 程式人生 > >CCF題目 Java實現

CCF題目 Java實現

最近老師讓我們大一刷一下CCF的題目,說是CCF要從娃娃抓起,於是寫了幾道題目,第一道和第二道題目比較輕鬆就能過,第三道題一般只能拿到不到一般測試樣例的分,但我在網上找對於ccf題目解析的部落格時,發現只有C++版本,於是想把自己過的幾個簡單題目的Java版本放上來,希望有人找Java版本時能有些幫助。

下面是第二道題目的一些Java實現:

2018_03_2    碰撞的小球

時間限制:1.0s

記憶體限制:256.0MB

問題描述:

數軸上有一條長度為L(L為偶數)的線段,左端點在原點,右端點在座標L處。有n個不計體積的小球線上段上,開始時所有的小球都處在偶數座標上,速度方向向右,速度大小為1單位長度每秒。
  當小球到達線段的端點(左端點或右端點)的時候,會立即向相反的方向移動,速度大小仍然為原來大小。
  當兩個小球撞到一起的時候,兩個小球會分別向與自己原來移動的方向相反的方向,以原來的速度大小繼續移動。
  現在,告訴你線段的長度L,小球數量n,以及n個小球的初始位置,請你計算t秒之後,各個小球的位置。

提示:

  因為所有小球的初始位置都為偶數,而且線段的長度為偶數,可以證明,不會有三個小球同時相撞,小球到達線段端點以及小球之間的碰撞時刻均為整數。

   同時也可以證明兩個小球發生碰撞的位置一定是整數(但不一定是偶數)。

輸入格式:輸入的第一行包含三個整數n, L, t,用空格分隔,分別表示小球的個數、線段長度和你需要計算t秒之後小球的位置。

第二行包含n個整數a1, a2, …, an,用空格分隔,表示初始時刻n個小球的位置。

輸出格式:輸出一行包含n個整數,用空格分隔,第i個整數代表初始時刻位於ai的小球,在t秒之後的位置。

樣例輸入:

3 10 5
4 6 8

樣例輸出:7 99

樣例說明

  初始時,三個小球的位置分別為4, 6, 8。

  一秒後,三個小球的位置分別為5, 7, 9。

  兩秒後,第三個小球碰到牆壁,速度反向,三個小球位置分別為6, 8, 10。

  三秒後,第二個小球與第三個小球在位置9發生碰撞,速度反向(注意碰撞位置不一定為偶數),三個小球位置分別為7, 9, 9。

  四秒後,第一個小球與第二個小球在位置8發生碰撞,速度反向,第三個小球碰到牆壁,速度反向,三個小球位置分別為8, 8, 10。

  五秒後,三個小球的位置分別為7, 9, 9。

資料規模和約定:對於所有評測用例,1 ≤ n ≤ 100,1 ≤ t ≤ 100,2 ≤ L ≤ 1000,0 < ai < L。L為偶數。
  保證所有小球的初始位置互不相同且均為偶數。

問題分析:

將主要程式碼,即小球移動過程的程式碼分成三部分,

1,小球的移動ballsMove();

2,判斷小球是否和邊界相撞checkBallsCollideBoundary();

3,判斷小球是否和其他小球相撞checkBallsCollideOther();

最後輸出每個小球的位置即可.

Java程式碼:

import java.util.Scanner;


public class Main2018_3_2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String inputNK = input.nextLine();
String[] arrNLT = inputNK.split("\\s");
int n = Integer.parseInt(arrNLT[0]);
int l = Integer.parseInt(arrNLT[1]);
int t = Integer.parseInt(arrNLT[2]);
String[] arrBallsStr = input.nextLine().split("\\s");
int[][] arrBalls = new int[n][2];
for(int i = 0;i<n;i++) {
arrBalls[i][0] = Integer.parseInt(arrBallsStr[i]);
arrBalls[i][1] = 1;
}
for(int i = 0;i<t;i++) {
ballsMove(l,arrBalls);
}
printBalls(arrBalls);
}

private static void ballsMove(int trackLength,int[][] arrBalls) {
for(int j = 0;j<arrBalls.length;j++) {
arrBalls[j][0] += arrBalls[j][1];
checkBallsCollideBoundary(arrBalls[j][0],trackLength,arrBalls,j);
checkBallsCollideOther(arrBalls[j][0],trackLength,arrBalls,j);
}
}

private static void checkBallsCollideBoundary(int nowPosition,int trackLength,int[][] arrBalls,int ballNum) {
if(nowPosition==trackLength || nowPosition == 0) {
arrBalls[ballNum][1] *= -1;
}
}

private static void checkBallsCollideOther(int nowPosition,int trackLength,int[][] arrBalls,int ballNum) {
for(int i = 0;i<arrBalls.length;i++) {
if(i==ballNum) {
continue;
}else {
if(arrBalls[i][0] == arrBalls[ballNum][0]) {
arrBalls[i][1] *= -1;
arrBalls[ballNum][1] *= -1;
}
}
}
}

private static void printBalls(int[][] arrBalls) {
for(int i = 0;i<arrBalls.length;i++) {
System.out.print(arrBalls[i][0] + " ");
}
}
}

系統結果:

 

2017_12_2    遊戲

時間限制:1.0s

記憶體限制:256.0MB

問題描述:有n個小朋友圍成一圈玩遊戲,小朋友從1至n編號,2號小朋友坐在1號小朋友的順時針方向,3號小朋友坐在2號小朋友的順時針方向,……,1號小朋友坐在n號小朋友的順時針方向。
  遊戲開始,從1號小朋友開始順時針報數,接下來每個小朋友的報數是上一個小朋友報的數加1。若一個小朋友報的數為k的倍數或其末位數(即數的個位)為k,則該小朋友被淘汰出局,不再參加以後的報數。當遊戲中只剩下一個小朋友時,該小朋友獲勝。
  例如,當n=5, k=2時:
  1號小朋友報數1;
  2號小朋友報數2淘汰;
  3號小朋友報數3;
  4號小朋友報數4淘汰;
  5號小朋友報數5;
  1號小朋友報數6淘汰;
  3號小朋友報數7;
  5號小朋友報數8淘汰;
  3號小朋友獲勝。

  給定nk,請問最後獲勝的小朋友編號為多少?

輸入格式:輸入一行,包括兩個整數nk,意義如題目所述。

輸出格式:輸出一行,包含一個整數,表示獲勝的小朋友編號。

樣例輸入:5 2

樣例輸出:3

資料規模和約定:對於所有評測用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 9。

問題分析:

這道題的關鍵在於每次淘汰一個小朋友後,下次的index會變化。

因為題目說淘汰小朋友,所以我覺得用List比較合適,用一個Kid類封裝小朋友的編號資訊,放在list中,判斷符合條件時remove,同時注意當報的數的增加量超過之前記錄的list的大小時,重新給增加量賦值,還有就是當remove時,因為宣告的用來算index的temp不會超過list的size,所以將temp-1即可,這樣下次遍歷時會從list的初始位置開始判斷。

Java程式碼:

import java.util.*;


public class Main2017_12_2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String inputNK = input.nextLine();
String[] arrNK = inputNK.split("\\s");
int n = Integer.parseInt(arrNK[0]);
int k = Integer.parseInt(arrNK[1]);
List<Kid> kidList = new ArrayList<>();
for(int i = 1;i<=n;i++) {
Kid kidTemp = new Kid(i);
kidList.add(kidTemp);
}
int numIncrease = 1;
int kidIndex = 0;
int lastSize = kidList.size();
int temp = 1;
int lastIncreaseSum = numIncrease;
while(kidList.size() > 1) {
kidIndex = (temp-1) % kidList.size();
String numIncreaseStr = numIncrease + "";
if(numIncrease % k == 0 || numIncreaseStr.endsWith(k+"")) {
kidList.remove(kidIndex);
temp--;
}
numIncrease++;
temp++;
if((numIncrease-lastIncreaseSum)==lastSize) {
temp = 1;
lastSize = kidList.size();
lastIncreaseSum = numIncrease;
}
}
System.out.println(kidList.get(0).number);
}
}
class Kid{
int number;
public Kid(int number) {
this.number = number;
}
}

系統結果:

 

2017_12_2    公共鑰匙盒

時間限制:1.0s

記憶體限制:256.0MB

問題描述:有一個學校的老師共用N個教室,按照規定,所有的鑰匙都必須放在公共鑰匙盒裡,老師不能帶鑰匙回家。每次老師上課前,都從公共鑰匙盒裡找到自己上課的教室的鑰匙去開門,上完課後,再將鑰匙放回到鑰匙盒中。
  鑰匙盒一共有N個掛鉤,從左到右排成一排,用來掛N個教室的鑰匙。一串鑰匙沒有固定的懸掛位置,但鑰匙上有標識,所以老師們不會弄混鑰匙。
  每次取鑰匙的時候,老師們都會找到自己所需要的鑰匙將其取走,而不會移動其他鑰匙。每次還鑰匙的時候,還鑰匙的老師會找到最左邊的空的掛鉤,將鑰匙掛在這個掛鉤上。如果有多位老師還鑰匙,則他們按鑰匙編號從小到大的順序還。如果同一時刻既有老師還鑰匙又有老師取鑰匙,則老師們會先將鑰匙全還回去再取出。
  今天開始的時候鑰匙是按編號從小到大的順序放在鑰匙盒裡的。有K位老師要上課,給出每位老師所需要的鑰匙、開始上課的時間和上課的時長,假設下課時間就是還鑰匙時間,請問最終鑰匙盒裡面鑰匙的順序是怎樣的?

輸入格式:輸入的第一行包含兩個整數N, K
  接下來K行,每行三個整數w, s, c,分別表示一位老師要使用的鑰匙編號、開始上課的時間和上課的時長。可能有多位老師使用同一把鑰匙,但是老師使用鑰匙的時間不會重疊。
  保證輸入資料滿足輸入格式,你不用檢查資料合法性。

輸出格式:輸出一行,包含N個整數,相鄰整數間用一個空格分隔,依次表示每個掛鉤上掛的鑰匙編號。

樣例輸入:

5 2
4 3 3
2 2 7

樣例輸出:1 43 2 5

樣例說明:

第一位老師從時刻3開始使用4號教室的鑰匙,使用3單位時間,所以在時刻6還鑰匙。第二位老師從時刻2開始使用鑰匙,使用7單位時間,所以在時刻9還鑰匙。
  每個關鍵時刻後的鑰匙狀態如下(X表示空):
  時刻2後為1X345;
  時刻3後為1X3X5;
  時刻6後為143X5;
  時刻9後為14325。

資料規模和約定:

對於30%的評測用例,1 ≤ N, K≤ 10, 1 ≤ wN, 1 ≤s, c ≤ 30;
  對於60%的評測用例,1 ≤ N, K ≤ 50,1 ≤ wN,1 ≤ s ≤ 300,1 ≤ c ≤ 50;
  對於所有評測用例,1 ≤ N, K ≤ 1000,1 ≤wN,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。

問題分析:

這道題的考察點集中在對還鑰匙時的描述,要保證還鑰匙時的順序,而且先還鑰匙,再借鑰匙,也就是在對每個時刻都要判斷一下checkReturnKeys(),checkLendKeys().

收穫:

把程式碼抽象成函式,避免整個程式碼雜亂難以看清思路,比如這個對每個時刻的操作就是分成三步,先checkReturnKeys(),再checkLendKeys(),最後pastTime++.

剩下的就是把每個要呼叫的函式寫清楚就好了,這樣整個程式碼的思路清晰多了。

Java程式碼:

 import java.util.*;


public class Main2017_09_2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String inputNK = input.nextLine();
String[] arrNK = inputNK.split(" ");
int n = Integer.parseInt(arrNK[0]);
int k = Integer.parseInt(arrNK[1]);

String[][] arrTeacher = new String[k][3];
int[][] arrTeacherInt = new int[k][3];
int[] arrKeys = new int[n];
for(int i = 0;i<n;i++) {
arrKeys[i] = i+1;
}
int lastTime = 0;
for(int i = 0;i<k;i++) {
arrTeacher[i] = input.nextLine().split("\\s");
for(int j = 0;j<3;j++) {
arrTeacherInt[i][j] = Integer.parseInt(arrTeacher[i][j]);
}
if((arrTeacherInt[i][1]+arrTeacherInt[i][2]) > lastTime) {
lastTime = arrTeacherInt[i][1]+arrTeacherInt[i][2];
}
}
int pastTime = 1;
while(pastTime<=lastTime) {
checkReturnKeys(pastTime,arrTeacherInt,arrKeys);
checkLendKeys(pastTime,arrTeacherInt,arrKeys);
pastTime++;
}
printKeys(arrKeys);
}

private static void checkReturnKeys(int pastTime,int[][] arrTeacherInt,int[] arrKeys) {
List<Teacher> teacherList = new ArrayList<>();
for(int i = 0;i<arrTeacherInt.length;i++) {
if((arrTeacherInt[i][1]+arrTeacherInt[i][2]) == pastTime) {
Teacher tempTeacher = new Teacher(arrTeacherInt[i][0],arrTeacherInt[i][1],arrTeacherInt[i][2]);
teacherList.add(tempTeacher);
}
}
Collections.sort(teacherList);
returnKeys(teacherList,arrKeys);
}

private static void checkLendKeys(int pastTime,int[][] arrTeacherInt,int[] arrKeys) {
for(int a = 0;a<arrTeacherInt.length;a++) {
if(pastTime==arrTeacherInt[a][1]) {
for(int b = 0;b<arrKeys.length;b++) {
if(arrKeys[b] == arrTeacherInt[a][0]) {
arrKeys[b] = 0;
break;
}
}
}
}
}

private static void printKeys(int[] keys) {
for(int i = 0;i<keys.length;i++) {
System.out.print(keys[i]+" ");
}
}

private static void returnKeys(List<Teacher> teacherList,int[] arrKeys) {
for(int a = 0;a < teacherList.size();a++) {
for(int b = 0;b<arrKeys.length;b++) {
if(arrKeys[b]==0) {
arrKeys[b] = teacherList.get(a).keyNum;
break;
}
}
}
}
}


class Teacher implements Comparable<Teacher>{
int keyNum;
int startTime;
int endTime;
Teacher(int keyNum,int startTime,int endTime){
this.keyNum = keyNum;
this.startTime = startTime;
this.endTime = endTime+startTime;
}
@Override
public int compareTo(Teacher otherTeacher) {
int value = this.keyNum - otherTeacher.keyNum;
return value;
}
}

系統結果: