藍橋杯 歷屆試題 剪格子Python實現(dfs 回溯)

資源限制
時間限制:1.0s 內存限制:256.0MB
問題描述
如下圖所示,3 x 3 的格子中填寫了一些整數。

±-–±-+
|10
1|52|
±-***–+
|20|30
1|
*******–+
| 1| 2| 3|
±-±-±-+
我們沿着圖中的星號線剪開,得到兩個部分,每個部分的數字和都是60。

本題的要求就是請你編程判定:對給定的m x n 的格子中的整數,是否可以分割爲兩個部分,使得這兩個區域的數字和相等。

如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。

如果無法分割,則輸出 0。

輸入格式
程序先讀入兩個整數 m n 用空格分割 (m,n<10)。

表示表格的寬度和高度。

接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000。

輸出格式
輸出一個整數,表示在所有解中,包含左上角的分割區可能包含的最小的格子數目。
樣例輸入1
3 3
10 1 52
20 30 1
1 2 3
樣例輸出1
3
樣例輸入2
4 3
1 1 1 1
1 30 80 2
1 1 1 100
樣例輸出2
10

分析:
舉例第二個:
在這裏插入圖片描述最終輸出的答案是10,就是紅色塊塊的個數。題目要求是輸出包含左上角的最少塊數。

我們可以讓搜索從左上角出發,這樣遍歷出來的每一種方案都是包含左上角塊塊的。

深搜的過程中,肯定要滿足的是,搜出來的方案和是總和的一半。所以在輸入數據的時候就將總和算出來。然後在深搜到大於總和的一半的值時候,就可以剪枝。

深搜的時候,可以上下左右。只要這個數字沒有用過。
在這裏插入圖片描述

深搜的出口是當搜到的和是總和一半的時候。

AC代碼:

while True:
    try:
        # n行m列
        m, n = map(int, input().split())
        s = []
        Sum = 0
        for i in range(n):
            s.append(list(map(int, input().split())))
            Sum += sum(s[i])
        used = [[0 for i in range(m)] for j in range(n)]
        ans = 100


        def dfs(i, j, temp_sum, cnt):
            global ans
            if temp_sum > Sum // 2:
                return
            if temp_sum == Sum // 2:
                ans = min(ans, cnt)
                return

            used[i][j] = 1
            # 如果現在不是最後一行,那麼可以往下走
            if i + 1 < n and used[i+1][j] == 0:
                dfs(i + 1, j, temp_sum + s[i][j], cnt + 1)
            # 如果現在不是最頂上的一行,那麼可以往上走
            if i - 1 >= 0 and used[i - 1][j] == 0:
                dfs(i - 1, j, temp_sum + s[i][j], cnt + 1)
            # 如果現在不是最左邊的一列,那麼可以往左邊走
            if j - 1 >= 0 and used[i][j - 1] == 0:
                dfs(i, j - 1, temp_sum + s[i][j], cnt + 1)
            # 如果現在不是最右邊的一列,那麼可以往右邊走
            if j + 1 < m and used[i][j + 1] == 0:
                dfs(i, j + 1, temp_sum + s[i][j], cnt + 1)

            # 執行到這說明s[i][j]這個數字不行,還原爲未使用狀態
            used[i][j] = 0


        dfs(0, 0, 0, 0)
        if ans<100:
            print(ans)
        else:
            print(0)
    except:
        break

編程小白歡迎指點~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章