【回溯】B036_LQ_剪格子(第二次到原点时不计数)

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

输出
输出一个整数,表示在所有解中,包含左上角的分割区可能包含的最小的格子数目

样例输入
3 3
10 1 52
20 30 1
1 2 3
样例输出
3
方法一:回溯

递归可能会两次到达 (0, 0),故第二次到达时,不计

#include
using namespace std;
#define N 15

const int INF=100, d[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
int n, m, c, sum, ans=INF, book[N][N], g[N][N]; 
void dfs(int i, int j, int c, int s) {
    if (s==sum/2 && c<ans) {
        ans=c;
    } 
    for (int k=0; k<4; k++) {
        int ni=i+d[k][0], nj=j+d[k][1];
        if (ni>=0 && ni<n && nj>=0 && nj<m && !book[ni][nj] && s+g[ni][nj]<=sum/2) {
            book[ni][nj]=1;
            if (ni==0 && nj==0) dfs(ni, nj, c, s); 
            else                dfs(ni, nj, c+1, s+g[ni][nj]);
            book[ni][nj]=0;
        }
    }
}
int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    cin>>m>>n;
    for (int i=0; i<n; i++)
    for (int j=0; j<m; j++) {
        cin>>g[i][j]; sum+=g[i][j];
    }
    if (sum%2==1) {
        cout << 0;
    } else {
        dfs(0,0,1,g[0][0]);
        cout << (ans==INF ? 0 : ans);
    }
    return 0;
}

你可能感兴趣的:(#,【回溯】)