格子を切る
写真の赤い線に沿って切り取り、2つの部分を取得しました。各部分の数の合計は60です。
この質問の要件は、指定されたmxnグリッドの整数を2つの部分に分割して、2つの領域の数値の合計が等しくなるかどうかを判断するようにプログラムするように依頼することです。
複数の解がある場合は、左上のグリッドを含む領域に含まれるグリッドの最小数を出力してください。
除算できない場合は0を出力しますプログラムの入力および出力形式の要件:
プログラムは、最初にスペース(m、n <10)で区切られた2つの整数mnを読み取り
、テーブルの幅と高さを示します。
次は、スペースで区切られたm個の正の整数を持つn行です。各整数は10000以下です。
プログラムの出力:すべてのソリューションで、左上隅のパーティション領域に含まれる可能性のあるグリッドの最小数。例:
ユーザー入力:
3 3
10 1 52
20 30 1
1 2 3プログラム出力:
3別の例:
ユーザー入力:
4 3
1 1 1 1
1 30 80 2
1 1 1100プログラム出力:
10
問題分析:
再帰+バックトラック+剪定
アイデア:グリッドで詳細検索を実行するには、再帰を使用し、次に状態の変更は各時間の座標とレコードの合計です。カウントは、実行されたステップ数を記録するために使用されます。終了は、グリッドの合計値がすべての合計を超えています。半分の時間で直接返すことができ、全体が合計の半分に等しい場合、この時間の半分に達したステップ数が最小であるかどうかを比較する必要があります。前のステップと比較すると、同じ状態の再帰呼び出しでは、各ステップに4つあります。4方向の場合、4方向のグリッドが再帰的に呼び出され、判断条件にも注意する必要があります。
一般に、グラフの走査では、元のパスを繰り返すことができない(走査を繰り返すことができない場合)ことを考慮すると、アドレスが訪問されたかどうかを記録するために別のスペースを申請する必要があることに注意してください。つまり、vis配列が再度開かれ、vis配列は訪問されません。訪問されたものは0で、訪問されたものは1です。
#include <iostream>
#include <algorithm>
using namespace std;
int m, n;
int g[10][10];
int vis[10][10]; //记录走过的状态
int total;
int res = 1000;
int count;
void f(int i, int j, int sum, int count){ //变化状态 ->参数
//边界,出口条件,当sum和大于总的一半时可以返回
if(sum > total / 2){
return ;
}
if(sum == total / 2){ //当sum 等于总的一半时,可以剪了,那么把这里
res = min(res, count);
return;
}
vis[i][j] = 1; //该格子被访问过了
//下一步的四个分支
if(i+1 <= n-1 && vis[i+1][j] == 0){ //保证下一步的格子没有走过
f(i+1, j, sum+g[i][j], count+1);
}
if(i-1 >= 0 && vis[i-1][j] == 0){
f(i-1, j, sum+g[i][j], count+1);
}
if(j+1 <= m-1 && vis[i][j+1] == 0){
f(i, j+1, sum+g[i][j], count+1);
}
if(j-1 >= 0 && vis[i][j-1] == 0){
f(i, j-1, sum+g[i][j], count+1);
}
vis[i][j] = 0;
}
int main(int argc, char** argv) {
cin >> m >> n;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin >> g[i][j];
total += g[i][j];
}
}
f(0, 0, 0, 0);
if(res != 1000){
cout << res;
}else{
cout << "0";
}
return 0;
}