历届试题 剪格子 IDA*

时间:2024-08-18 16:07:08

思路:限制当前能剪下的最大格子数,保证能得到最少数目。IDA*的典型运用。

AC代码

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const int maxn = 10 + 5;
int vis[maxn][maxn], a[maxn][maxn];
int n, m, maxd, goal;

const int dx[] = {0,0,-1,1};
const int dy[] = {1,-1,0,0};

// IDA*
int w;
int dfs(int x, int y, int sum, int cnt) {
	if(sum == goal) return 1;
	if(cnt >= maxd) {
		w = min(w, sum);
		return 0;
	}
	vis[x][y] = 1;
	for(int i = 0; i < 4; ++i) {
		int px = x + dx[i], py = y + dy[i];
		if(px < 0 || py < 0 || px >= n || py >= m || vis[px][py]) continue;
		if(sum + a[px][py] > goal) continue;
		if(dfs(px, py, sum + a[px][py], cnt + 1)) return 1;
	}
	vis[x][y] = 0;
	return 0;
}

int main() {
	while(scanf("%d%d", &m, &n) == 2) {
		int sum = 0;
		for(int i = 0; i < n; ++i)
			for(int j = 0; j < m; ++j) {
				scanf("%d", &a[i][j]);
				sum += a[i][j];
			}
		if(sum & 1) {
			printf("0\n");
			continue;
		}
		memset(vis, 0, sizeof(vis));
		goal = sum / 2;
		int flag = 0;
		for(maxd = 1; maxd < n*m; ++maxd) {
			w = inf;
			if(dfs(0, 0, a[0][0], 1)) {
				flag = 1;
				printf("%d\n", maxd);
				break;
			}
			if(w > goal) break;
		}
		if(!flag) printf("0\n");
	}

	return 0;
}

如有不当之处欢迎指出!