0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Fortran】Fortranで回文判定プログラムを実装する (随時更新)

Last updated at Posted at 2023-10-07

回文に関する問題はいくつか種類があると思うので、随時機能を追加します。

概要

Atcoderのコンテストでは、回文に関する問題がしばしば出題されます。
回文に関する問題が出題される度、1からプログラムを実装するのは大変です。

本記事では回文を判定するプログラムを作成し、今後のAtCoderのコンテストに備えます。

アルゴリズム

回文の判定方法

回文の判定は中心とする文字から外側に向けて1文字ずつ対称に比較・判定の範囲を広げていくことで行います。

1番初めの比較・判定対象は、以下に示す「隣り合う文字の場合」と、「間に1文字挟む場合」の2種類があります。
「間に1文字挟む場合」は、中心の文字だけで1文字分の回文が成立していることに注意が必要です。

image.png

image.png

回文長さの判定方法

文字列に含まれる回文の文字数を探す場合には、1番初めに比較・判定対象とする位置(上図の2や1)を1文字づつずらしながら、回文の長さを調べることで行います。

プログラム例

例1:文字列中に含まれる回文の最大長さを調べる

ABC320bを例題に、文字列Sの中で成立している回文の最大長さを出力します。

プログラム
program ex_kaibun
    implicit none
    character(100) mozi
    integer cnt_max

    !入力
    !write (*, '(a)', advance='no') '文字列の入力 >>'
    read (*, *) mozi
    !処理
    cnt_max = -1
    call cal_kaibun(mozi, cnt_max)
    !出力
    write (*, '(i0)') cnt_max

contains
    subroutine cal_kaibun(mozi, cnt_max)
        implicit none
        character(100) mozi
        integer cnt_max
        integer n, i, cnt, left, right

        !文字列の長さ
        n = len_trim(mozi)

        !回文のmax
        do i = 1, n - 1
            !中心なしの場合
            cnt = 0; left = i; right = i + 1
            call search_kaibun(mozi, n, left, right, cnt)
            cnt_max = max(cnt_max, cnt)

            !中心ありの場合
            cnt = 1; left = i; right = i + 2
            if (left <= 0 .or. right > N) return
            call search_kaibun(mozi, n, left, right, cnt)
            cnt_max = max(cnt_max, cnt)
        end do
    end subroutine cal_kaibun

    subroutine search_kaibun(mozi, n, left, right, cnt)
        integer n, left, right, cnt
        character(n) mozi

        !回文長さの測定
        do
            !文字列の範囲内か判定
            if (left <= 0 .or. right > N) return

            !回文判定
            if (mozi(left:left) == mozi(right:right)) then
                cnt = cnt + 2
            else
                return
            end if
            left = left - 1
            right = right + 1
        end do
    end subroutine
end program ex_kaibun

例2:指定した長さ以上の回文が存在するか調べる

文字列の中に指定した長さ以上の回文が存在するかを調べます。
回文判定の前後に処理を行うことを想定して、文字列はASCIIコード(数字)に変換してから回文を調べます。

プログラム
program ex_kaibun2
    implicit none
    character(100) mozi
    integer, allocatable::num(:)
    integer n, k, cnt, i

    !入力
    write (*, '(a)', advance='no') '文字列の入力 >>'
    read (*, *) mozi
    n = len_trim(mozi)
    allocate (num(n))

    !文字列を数字に変換
    do i = 1, n
        num(i) = ichar(mozi(i:i))
    end do

    !回文判定
    k = 4
    call cal_kaibun(num, n, k, mod(k, 2), cnt)
    if (cnt == k) then
        write (*, *) 'Yes'
    else
        write (*, *) 'No'
    end if

contains
    subroutine cal_kaibun(arr, n, k, search_case, cnt)
        implicit none
        integer n, arr(n), k, search_case
        integer cnt, left, right
        integer i

        !回文判定
        select case (search_case)
        case (0) !偶数範囲
            do i = 1, n - 1
                cnt = 0; left = i; right = i + 1
                if (left <= 0 .or. right > N) return
                call search_kaibun(arr, n, k, left, right, cnt)
                if (cnt >= k) then
                    return
                end if
            end do
        case (1) !奇数範囲
            do i = 1, n - 1
                cnt = 1; left = i; right = i + 2
                if (left <= 0 .or. right > N) return
                call search_kaibun(arr, n, k, left, right, cnt)
                if (cnt >= k) then
                    return
                end if
            end do
        end select
    end subroutine cal_kaibun

    subroutine search_kaibun(arr, n, k, left, right, cnt)
        integer arr(n), n, k, left, right, cnt
        !回文長さの測定
        do
            !文字列の範囲内か判定
            if (left <= 0 .or. right > N .or. cnt >= k) return
            !回文判定
            if (arr(left) == arr(right)) then
                cnt = cnt + 2
            else
                return
            end if
            left = left - 1
            right = right + 1
        end do
    end subroutine
end program ex_kaibun2
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?