AOJ PG入門 #4

## 問1.２つの整数 a と b を読み込んで、以下の値を計算するプログラムを作成して下さい
- a ÷ b ： d (整数)
- a ÷ b の余り ： r (整数)
- a ÷ b ： f (浮動小数点数)
- d, r, f を１つの空白で区切って１行に出力して下さい。fについては、0.00001以下の誤差があってもよいものとします。

### PHP
```AOJ.php
<?php
fscanf(STDIN,"%d %d",$a,$b);
$d = intdiv($a,$b);
$r = $a%$b;
$f = $a/$b;
printf("%d %d %f\n",$d,$r,$f);
?>
```
- 整数除算のとき→intvalとintdivは同じ動作だが、intdivの方が明確に整数除算を意図しているため、可読性が向上
- a / b はデフォルトで浮動小数点数として計算される

### Java
```AOJ.java
import java.util.Scanner;
public class Main{
    public static void main(String[]args){
      Scanner sc = new Scanner(System.in);
      int a = sc.nextInt();
      int b = sc.nextInt();
      int d = a/b;
      int r = a%b;
      double f = (double)a/b;
      System.out.printf("%d %d %f",d,r,f);
      sc.close();
    }
}
```
## 問2.半径 r の円の面積と円周の長さを求めるプログラムを作成して下さい。
面積と円周の長さを１つの空白で区切って１行に出力して下さい。出力は浮動小数点数とし、0.00001 以下の誤差を含んでもよいものとします。
### PHP
```AOJ.php
<?php
fscanf(STDIN,"%f",$r);
printf("%f %f\n",M_PI*$r*$r,2*M_PI*$r);
?>
```
- M_PIはPHPの定義済み定数。πの近似値を返す。

### Java
```AOJ.java
import java.util.Scanner;
public class Main{
    public static void main(String[]args){
       Scanner sc = new Scanner(System.in);
       double r = sc.nextDouble();
       System.out.printf("%f %f\n",r*r*Math.PI,2*r*Math.PI);
       sc.close();
    }
}

```
- 定義済み定数Math.PIは円周率を返す

## 問3.２つの整数 a, b と１つの演算子 op を読み込んで、a op b を計算するプログラムを作成して下さい。
ただし、演算子 op は、"+"(和)、"-"(差)、"*"(積)、"/"(商)、のみとし、割り算で割り切れない場合は、小数点以下を切り捨てたものを計算結果とします。
- 入力は複数のデータセットから構成されています。各データセットの形式は以下のとおりです：
a op b
- op が '?' のとき 入力の終わりを示します。このケースの出力は行ってはいけません。
- 各データセットについて、計算結果を１行に出力して下さい。
### PHP
```AOJ.php
<?php
while($input=fgets(STDIN)){
    list($a,$op,$b) = explode(" ",trim($input));
    $a = (int)$a;
    $b = (int)$b;

   if($op == "?")break;
   switch($op){
       case "+" : $ans = $a + $b;
       break;
       case "-" : $ans = $a - $b;
       break;
       case "/" : $ans = floor($a / $b);
       break;
       case "*" : $ans = $a * $b;
       break;
   }
   echo "$ans\n";
}
?>
```
- 演算子は文字列扱い
- 小数点以下切り捨て→floor関数

今回入力が　  a op bのように空白を入れて入力しているので、例えば3 + 5 と入力を受け取れば
trimで文字列の前後の空白（および改行）を削除
→explodeで空白（スペース）を区切り文字として、文字列「3 + 5」を分割
→分割された要素のそれぞれをlist関数でそれぞれの変数に格納

としている。
しかし入力が　3+5のように空白のないものだった場合、explodeは使えないので正規表現で分割する。

例
```example.php
$line = "3+5"; // スペースなし
$line = trim($line); // "3+5"

// 正規表現で演算子を分割
if (preg_match('/(\d+)([+\-*/])(\d+)/', $line, $matches)) {
    $a = (int)$matches[1];
    $op = $matches[2];
    $b = (int)$matches[3];
    
    // 演算の処理（switch文など）
    switch ($op) {
        case '+': $c = $a + $b; break;
        case '-': $c = $a - $b; break;
        case '*': $c = $a * $b; break;
        case '/': $c = floor($a / $b); break;
    }
    echo $c . "\n";
}

```
- preg_match() は 正規表現にマッチした部分を $matches 配列に格納する関数。
- () で囲んだ部分（キャプチャグループ）は、それぞれ $matches[1], $matches[2], ... に格納される。キャプチャグループを使わないとマッチした全体のみ取得。
- 書式は　
```
preg_match(パターン, 検索対象の文字列, マッチ結果を格納する配列);
```
成功すると preg_match() は 1 を返し、配列にその結果が入る。失敗すると 0 を返す。
- \d+=一個以上の数字（\d=数字、+=一回以上）
- []＝どれかひとつ
例えば＄line = "3+5" の場合、上記の＄matches配列の中身は以下のようになる
```
$matches = [
    0 => "3+5",   // 全体のマッチ部分（入力全体）
    1 => "3",     // 1つ目の `(\d+)` にマッチ（最初の数値）
    2 => "+",     // `([+\-*/])` にマッチ（演算子）
    3 => "5"      // 2つ目の `(\d+)` にマッチ（次の数値）
];
```

### Java
```AOJ.java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        while (true) {
            String input = sc.nextLine(); 
            String[] math = input.split(" "); 
            
            if (math[1].equals("?")) break; // "?" ならループ終了
            
            int a = Integer.parseInt(math[0]); 
            int b = Integer.parseInt(math[2]); 
            int ans = 0;
            
            switch (math[1]) {
                case "+": ans = a + b; break;
                case "-": ans = a - b; break;
                case "*": ans = a * b; break;
                case "/": ans = a / b; break; 
            }
            
            System.out.printf("%d%n", ans); 
        }
        
        sc.close();
    }
}
```
- split() の引数は 正規表現 なので、 " "（ダブルクォートの空白）
- Javaでは文字列を比較する際は　== ではなく equals() を使う。
- math[0] や math[2] は String 型 なので、そのまま計算できない。
→Integer.parseInt() でString型をint 型に変換

### 別解
```other.java
import java.util.Scanner;
     
    /* Name of the class has to be "Main" only if the class is public. */
    class Main{
    	public static void main(String[] args) {
    		Scanner scanner = new Scanner(System.in);
    		while(scanner.hasNext()){          //入力がある間はループ継続
    		 long a = scanner.nextLong();
    		 String str = scanner.next();
    		 long b = scanner.nextLong();
    		 
    		 switch(str) {
    		 case "+":
    			 System.out.println(a+b);
    			 break;
    		 case "-":
    			 System.out.println(a-b);
    			 break;
    		 case "/":
    			 System.out.println(a/b);
    			 break;
    		 case "*":
    			 System.out.println(a*b);
    			 break;
    			 default:
    				 break;
    		 }
    		}
    	}
     //　
    }

```
- hasNext関数→次の入力があるかどうかを確認するメソッド。次のトークン (単語) があるなら true を返す。
入力が終わっていたら false を返す。next() を呼び出す前に使うとエラーを防げる

- Scanner クラスの next() は、スペースや改行で区切られた次の文字列を取得するメソッド。
- nextInt() や nextLong() は、空白 (スペース, タブ) や改行を区切りとして、次の数値だけを取得する。
数値の後に空白 ( ) や改行 (\n) があると、そこで読み取りを終了し、次の入力を待つ。
```other2.java
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a, b;
        
        while (true) {
            a = sc.nextInt();  // 整数aを入力
            String c = sc.next();  // 演算子をStringとして取得
            b = sc.nextInt();  // 整数bを入力
            
            if (c.equals("?")) break;  // 演算子が「?」の場合、ループを終了
            
            // 演算子に応じて計算
            if (c.equals("+")) {
                System.out.println(a + b);
            } else if (c.equals("-")) {
                System.out.println(a - b);
            } else if (c.equals("*")) {
                System.out.println(a * b);
            } else if (c.equals("/")) {
                System.out.println(a / b);
            }
        }
    }
}

```
## 問4.n個の整数ai(i=1,2,...n)を入力し、それらの最小値、最大値、合計値を求めるプログラムを作成してください。
- １行目に整数の数nが与えられます。２行目にn個の整数aiが空白区切りで与えられます。
- 最小値、最大値、合計値を空白区切りで１行に出力してください。
### PHP
```AOJ.php
<?php
 $n = intval(trim(fgets(STDIN)));   
 $a = array_map('intval',explode(" ",(trim(fgets(STDIN)))));
 printf("%d %d %d\n",min($a),max($a),array_sum($a));
?>
```
- explodeで文字列の要素から成る配列→array_mapで全要素をintval適用で整数にして整数要素から成る配列にする。


### Java
```AOJ.java
import java.util.Scanner;
public class Main{
    public static void main(String[]args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[]a = new int[n];
        for(int i = 0;i<n;i++){
            a[i] = sc.nextInt();
        }
        int mi = 1000000;
        int ma = -1000000;
        
        int sum = 0;
        for(int j = 0;j<a.length;j++){
            mi = Math.min(mi,a[j]);
            ma = Math.max(ma,a[j]);
            sum += a[j];
        }
       
        System.out.println(mi + " " + ma + " " + sum);
        sc.close();
    }
}
```
- sumの型→intにしたら大きな数の合計で整数オーバーフローエラー。注意！