【ABC325】FortranでA,B,C問題

## 目次
  - [A - Takahashi san](#a---takahashi-san)
  - [B - World Meeting](#b---world-meeting)
  - [C - Sensors](#c---sensors)


## A - Takahashi san
### 問題
ある人の苗字と名前がそれぞれ文字列 S,T として与えられます。
苗字、スペース、敬称（san）をこの順に連結した文字列を出力してください。

>**制約**
>1. S , T は長さ 1 以上 10 以下満たす文字列
>2. S , T は先頭の文字は英大文字
>3. S , T は先頭以外の文字は英小文字

詳細はこちらです。

https://atcoder.jp/contests/abc325/tasks/abc325_a


### 解説
**【フローチャート】**
S に san を付けて出力します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/bbf732d4-849e-e2cf-2eaf-db365daabf79.png" width= 35%>


### プログラム例
```Fortran
program abc325a
    ! S：名字
    ! T：名前
    implicit none
    character(10) S, T

    !入力
    read (*, *) S, T

    !出力
    write (*, ('(a,1x,a)')) trim(S), 'san'
end program abc325a
```



## B - World Meeting
### 問題
N 個の拠点があり、 拠点 i には $W_i$ 人の社員が所属しており、世界標準時で 0 時のとき拠点 i は $X_i$ 時です。
全拠点で一斉に会議を１時間開く時、会議に参加できる社員の数の最大値を求めてください。
ただし、 会議は現地時間で9:00-18:00 の時間帯に開けれなければなりません。

>**制約**
>1. $1≤N≤1000$
>2. $1≤W_i≤10^6$
>3. $0≤X_i<24$
>4. 入力は全て整数

詳細はこちらです。

https://atcoder.jp/contests/abc325/tasks/abc325_b


### 解説
**【フローチャート】**
0 ~ 24　時の間の中で総当たりで調べ、参加できる最大の人数を調べます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/c882aea3-26c3-6eac-a204-09edc4a15160.png" width=50%>

**【補足】**
※1
0 ~ 24　時の間の中で総当たりで調べ、参加できる最大の人数を調べます。
ただし**入力は全て整数**であるため、時差は必ず**１時間単位**となります。
従って人数の増減は X時00分おきに生じるため、会議の開始時間に **分、秒** を考慮する必要はありません。

※2
各拠点の現地時間を算定します。
会議の開始時間・時差によって、**現地時間が日を跨ぐ可能性があること**に注意が必要です。

※3
各時間の会議の参加人数を比較し、最大参加人数を更新します。
更新には、`MAX関数`を使用します。


### プログラム例
```Fortran

program abc325b
    !W         ：拠点にいる社員の数
    !X         ：拠点のタイムゾーン
    !N         ：拠点の数
    !tmp_member：各時間での参加できる社員の数
    !max_member：参加できる社員の最大人数
    !time      ：タイムゾーンを考慮した会議の開催時間
    implicit none
    integer(16) N, i, j, tmp_member, max_member, time
    integer(16), allocatable::W(:), X(:)

    !入力
    read (*, *) N
    allocate (W(N), X(N))
    do i = 1, N
        read (*, *) W(i), X(i)
    end do

    !会議に参加できる人数の集計
    tmp_member = 0; max_member = 0
    do i = 0, 23
        tmp_member = 0
        do j = 1, N
            time = X(j) + i
            if (time >= 24) time = time - 24
            if (9 <= time .and. time + 1 <= 18) then
                tmp_member = tmp_member + W(j)
            else
            end if
        end do
        max_member = max(tmp_member, max_member)
    end do

    !結果の出力
    write (*, *) max_member
end program abc325b
```



## C - Sensors
### 問題
H 行 W 列のマス目の上に 0 個以上のセンサが配置されています。

センサはマスの値が `#`の場所に配置されています。

センサは上下左右斜めに隣接しているマス目のセンサと連動し、1つのセンサとして動作します。
連動するセンサを一つのセンサと見なしたとき、このマス目の上にあるセンサの個数を求めてください。

>**制約**
>1. $1≤H,W≤1000$
>2. H,W は整数
>3. $S_i$ は各文字が `#` または `.` である長さ W の文字列

詳細はこちらです。

https://atcoder.jp/contests/abc325/tasks/abc325_c


### 解説
**【フローチャート】**
各マスを順番に調べ、センサの数を集計します。
隣接するセンサを一纏めにカウントする際、重複してカウントしない様に注意が必要です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3259514/a5ca995a-4929-5cb0-02b4-b1fd358c7e91.png" width= 50%>

**【補足】**
※1
マス( i , j )がセンサでかつ、未カウントのセンサかどうかを判定します。
既にカウント済みのセンサの場合は、周辺のセンサと一体に動いているため、新たにセンサとしてカウントする必要はありません。

※2
マス( i , j )がセンサでかつ、未カウントのセンサの場合は周辺に連動するセンサがあるかを判定します。
判定には`DFS`を用います。


### プログラム例
```Fortran
module global_abc325c
    !S         ：センサの配置
    !cnt       ：センサの数
    !H,W       ：センサのサイズ
    !check_root：チェックしたマスの管理
    implicit none
    character(1), allocatable :: S(:, :)
    integer, allocatable::check_root(:, :)
    integer cnt, H, W
end module
program abc325c
    use global_abc325c
    implicit none
    integer i, j

    !入力
    read (*, *) H, W
    allocate (S(H, W), check_root(H, W))
    do i = 1, H
        read (*, '(*(a1))') S(i, 1:W)
    end do

    !センサの個数の集計
    cnt = 0
    do i = 1, H
        do j = 1, W
            if (S(i, j) == '#' .and. check_root(i, j) == 0) then
                !write (*, *) 'A', i, j
                cnt = cnt + 1
                call move(i, j)
            end if
        end do
    end do

    !結果の出力
    write (*, *) cnt

contains
    recursive subroutine move(i, j)
        integer i, j
        if (i > 0 .and. i <= H .and. j <= W .and. j > 0) then
            !移動先が壁
            if (S(i, j) == '.') return
            !移動先が訪問済：終了
            if (check_root(i, j) == 1) then
                return
            else
                !移動先が道
                !write (*, *) i, j
                check_root(i, j) = 1
                call move(i + 1, j) !下
                call move(i - 1, j) !上
                call move(i, j + 1) !右
                call move(i, j - 1) !左
                call move(i - 1, j - 1) !左斜め上
                call move(i - 1, j + 1) !右斜め上
                call move(i + 1, j - 1) !左斜め下
                call move(i + 1, j + 1) !右斜め下
            end if
        else
            return
        end if
    end subroutine
end
```


## 感想
- A：3分、B：60分、C：29分でした。
- B 問題の実装に苦戦してます。単純に全探索するか、計算量を減らす処理を挟むかで葛藤し、提出が遅くなってしまいます...