刚开始想了一种奇怪的方法去贪心,因为不是正确的就不贴了,然后T了……
题解写的是IDA*,其实是迭代加深和剪枝。
剪枝的地方有几处:
1.估价函数剪枝,还剩几种颜色估计几步
2.无效剪枝,如果当前这个颜色已经没有就不用走这一步了
整体的思路是这样的
把原图按照颜色做一个连通块,然后原图可以分为三个部分:和(1,1)连通的点、和(1,1)连通的点相邻的点、其他点
那么,每次只在这些和(1,1)连通点相邻的点上选取颜色,然后就是一个接近暴力的过程。
因为数组稍多,重复访问不可承受。所以采取每次枚举当前变换成的颜色,然后标记掉相邻的相同颜色的点。
每个点用它的连通块标号来判断是否已经访问过,避免访问整个8*8数组的情况。
失分点:
1. 根据数据范围应该猜测为搜索,然而一开始思路就错了。
2. 剪枝没有充分,特别是无效剪枝一块,不加就T了
学习处:
1. 搜索剪枝的范围会很小,大概猜测10以内为1s,20以内为2-3s
2. 剪枝分为:最优性剪枝、无效剪枝、估价函数剪枝等
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MAXN = 8 + 1;
int g[MAXN][MAXN], n;
bool vis[MAXN][MAXN], use[MAXN * MAXN];
int bccno[MAXN][MAXN], bcccnt, col[MAXN * MAXN];
int ans;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};
bool validPos(int x, int y){if(x >= 0 && x < n && y >= 0 && y < n) return true; else return false;}
int predit()
{
bool tcol[6];
for(int i = 0 ; i < 6 ; i++) tcol[i] = false;
int res = 0;
for(int i = 1 ; i <= bcccnt ; i++) if(tcol[col[i]] == false && use[i] == false) tcol[col[i]] = true, res++;
return res;
}
int getcnt(int c)
{
int res = 0;
for(int i = 0 ; i < n ; i++) {
for(int j = 0 ; j < n ; j++) {
if(g[i][j] == c && use[bccno[i][j]] == false) {
int ok = 0;
for(int k = 0 ; k < 4 ; k++) {
int tx = i + dx[k], ty = j + dy[k];
if(use[bccno[tx][ty]]) {
ok = 1;
break;
}
}
if(ok) res++;
}
}
}
return res;
}
bool dfs(int dep)
{
int pre = predit();
// printf("ans = %d, dep = %d, pre = %d\n", ans, dep, pre);
if(dep == ans) {
if(pre == 0) return true;
else return false;
}
else if(dep + pre > ans) return false;
// printf("dep = %d, use = ");
// for(int i = 1 ; i <= bcccnt ; i++) printf("%d ", use[i]);
// puts("");
bool tuse[MAXN * MAXN];
memcpy(tuse, use, sizeof use);
for(int c = 0 ; c < 6 ; c++) {
if(getcnt(c) == 0) continue;
for(int i = 0 ; i < n ; i++) {
for(int j = 0 ; j < n ; j++) {
if(use[bccno[i][j]] == 0 && col[bccno[i][j]] == c) {
int ok = 0;
for(int k = 0 ; k < 4 ; k++) {
int tx = i + dx[k];
int ty = j + dy[k];
if(use[bccno[tx][ty]] == true) {
ok = 1;
break;
}
}
use[bccno[i][j]] = ok;
}
}
}
// system("pause");
if(dfs(dep + 1)) return true;
memcpy(use, tuse, sizeof tuse);
}
return false;
}
void dfsbcc(int x, int y, int mark)
{
for(int i = 0 ; i < 4 ; i++) {
int tx = x + dx[i];
int ty = y + dy[i];
if(validPos(tx, ty) && g[x][y] == g[tx][ty] && bccno[tx][ty] == 0) {
bccno[tx][ty] = mark;
dfsbcc(tx, ty, mark);
}
}
}
int main()
{
while(scanf("%d", &n) != EOF && n) {
for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) scanf("%d", &g[i][j]);
ans = 1;
for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) vis[i][j] = bccno[i][j] = 0;
bcccnt = 0;
for(int i = 0 ; i < n ; i++) {
for(int j = 0 ; j < n ; j++) {
if(bccno[i][j] == 0) {
bccno[i][j] = ++bcccnt;
dfsbcc(i, j, bcccnt);
col[bcccnt] = g[i][j];
}
}
}
for(int i = 1 ; i <= bcccnt ; i++) use[i] = false;
use[1] = true;
ans = 0;
while(dfs(0) == false) ans++;
printf("%d\n", ans);
}
return 0;
}