藍橋杯 歷屆試題 PREV-4 剪格子

問題描述

如下圖所示,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

 

思路分析:從題目和兩個案例可以看出,本題是典型的dfs(深度優先搜索)算法的題目。採用dfs+回溯的思路,從數組左上角即(0,0)開始搜索,累加當前數字,直到數字和爲總數字和的一半,返回走到數組當前位置的步數。值得說明的是,本題先讀入的m是列,而不是n(行)。具體思路請看代碼,附帶詳細註釋。

 

import java.util.Scanner;

/**
 * 
 * Created with MyEclipse
 * 
 * @Description 藍橋杯 歷屆試題 PREV-4 剪格子
 * @author Jun
 * @date 2020年4月16日
 */
public class Problem04 {

	static int[][] dir = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; // 方向右,下,左,上
	static boolean[][] user;
	static int[][] map;
	static n, m, ans = Integer.MAX_VALUE, sum = 0;

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		m = scan.nextInt();
		n = scan.nextInt();
		user = new boolean[n][m];
		map = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				map[i][j] = scan.nextInt();
				sum += map[i][j];
			}
		}
		if (sum % 2 == 0) { // 和爲偶數
//			for (int i = 0; i <= n/2; i++) {
//				for (int j = 0; j < m/2; j++) {
//					user[i][j]=true;
//					int temp = dfs(i, j, map[i][j]);
//					user[i][j]=false;
//					if (temp != 0) { // 獲取所有結果中的最小值
//						ans = Math.min(ans, temp);
//					}
//				
//				}
//			}
			user[0][0] = true;
			System.out.println(dfs(0, 0, map[0][0]));
//			System.out.println(ans);
		} else {
			System.out.println(0);
		}

	}

	public static boolean checkNext(int x, int y, int num) { // 檢查(x,y)是否允許走
		if (x < 0 || x >= n || y < 0 || y >= m) { // 數組越界
			return false;
		}
		if (user[x][y]) { // 該位置元素操作過
			return false;
		}
		if (num + map[x][y] > sum / 2) { // 走這一步超過了和的一半
			return false;
		}
		return true;

	}

	public static int dfs(int x, int y, int num) { // 代表搜索完點(x,y)時左上角的和sum
		if (num == sum / 2) {
			return 1;
		}
		for (int i = 0; i < 4; i++) {
			int nx = x + dir[i][0], ny = y + dir[i][1]; // 下一個點的座標
			if (!checkNext(nx, ny, num)) { // 下一個點不可以走
				continue;
			}
			// 下一步可以走
			user[nx][ny] = true;
			int res = dfs(nx, ny, num + map[nx][ny]); //dfs,遞歸探查下一個點
			if (res != 0) { // 產生結果,直接返回
				return res + 1;
			}
			user[nx][ny] = false;  //回溯
		}
		return 0;

	}

}

參考:https://www.cnblogs.com/yym2013/p/3526167.html

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