Fel*_*ipe 10 c++ algorithm backtracking
我有网格N×M,其中每个单元格用一种颜色着色.
当玩家点击颜色α网格的任何单元格时,网格最左上角的颜色为β的单元格接收颜色α,但不仅仅是:所有那些通过颜色连接到源的单元格仅使用颜色α或β的路径也接收颜色α.
应仅在水平和垂直方向上考虑单元之间的连接以形成路径.例如,当玩家点击左图中突出显示的单元格时,网格会在右侧接收图形的颜色.游戏的目标是使网格单色化.
输入描述
输入的第一行由2个整数N和M(1≤N≤4,1≤M≤5)组成,它们分别代表网格的行数和列数.下面的N行描述了网格的初始配置,用0到9之间的整数表示每种颜色.输入不包含任何其他行.
输出描述
打印包含单个整数的行,该整数表示播放器必须执行的最小点击次数才能使网格变为单色.
输入样本
1:
4 5
01234
34567
67890
901232:
4 5
01234
12345
23456
345673:
4 5
00162
30295
45033
01837
输出样本
1:
12
2:
7
3:
10
我正在尝试找回带回溯的解决方案(因为8秒的时间限制和网格的小尺寸).但它超出了时间限制.有些人刚刚在0秒时完成了它.
还有其他算法可以解决这个问题吗?
#include <stdio.h>
#include <string.h>
#define MAX 5
#define INF 999999999
typedef int signed_integer;
signed_integer n,m,mink;
bool vst[MAX][MAX];
signed_integer flood_path[4][2] = {
{-1,0},
{1,0},
{0,1},
{0,-1}
};
//flood and paint all possible cells... the root is (i,j)
signed_integer flood_and_paint(signed_integer cur_grid[MAX][MAX],signed_integer i, signed_integer j, signed_integer beta, signed_integer alpha, signed_integer colors[]){
//invalid cell
if (vst[i][j] || i < 0 || i >= n || j < 0 || j >= m)
return 0;
//mark existent colors
colors[cur_grid[i][j]] = 1;
//only alpha and beta colors counts
if (cur_grid[i][j] != beta && cur_grid[i][j] != alpha)
return 0;
//mark (i,j) as visited and change its color
vst[i][j] = true;
cur_grid[i][j] = alpha;
//floodit !
signed_integer ret = 1;
for (signed_integer k = 0; k < 4; k++)
ret += flood_and_paint(cur_grid,i + flood_path[k][0], j + flood_path[k][1], beta, alpha, colors);
//how many cells change
return ret;
}
void backtrack(signed_integer cur_grid[MAX][MAX],signed_integer k,signed_integer _cont, signed_integer alpha) {
//bigger number of clicks for this solution ? ... getting back
if(k >= mink)
return;
signed_integer colors[10];
memset(vst, false, sizeof(vst));
memset(colors, 0, sizeof(colors));
signed_integer beta = cur_grid[0][0];
signed_integer cont = flood_and_paint(cur_grid, 0, 0, beta, alpha, colors);
//there are alpha colors to change and no beta colors to change
colors[alpha] = 1;
colors[beta] = 0;
//all squares on same color
if (cont == n * m) {
mink = k;
return;
}
//this solution is equals to another ? ... getting back
if (cont == _cont)
return;
++k;//new click
//copy this matrix and backtrack
signed_integer copy[MAX][MAX];
for (signed_integer c = 0; c < 10; ++c){
if (colors[c] && c != cur_grid[0][0]) {
memcpy(copy, cur_grid,n*m*sizeof(signed_integer));
backtrack(copy,k,cont,c);
}
}
}
void cleanBuffer(){
while (getchar() != '\n');
}
int main(void) {
signed_integer grid[MAX][MAX];
scanf("%d %d",&n,&m);
for (signed_integer i = 0; i < n; ++i) {
cleanBuffer();
for (signed_integer j = 0; j < m; ++j){
grid[i][j] = getchar() - '0';
}
}
mink = INF;
backtrack(grid,0, 0, grid[0][0]);
printf("%d\n",mink);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,单元格是其原始颜色或最后选择的颜色.
这意味着我们可以通过20位表示电路板的当前状态(标记每个4*5单元是否包含原始颜色),以及0到9范围内的数字,选择最后一种颜色.
这导致最多可探索1000万个州.回溯函数可以避免在它到达已经访问过的状态时必须递归.我希望这种改变可以使你的解决方案更快.
通过20位掩码和最后一种颜色表示状态也使状态更新和恢复更快,因为只需要更改2个数字而不是整个板的memcpy.
归档时间: |
|
查看次数: |
834 次 |
最近记录: |