题目背景:NOIP 2009提高组
解法思路:暴力肯定TLE.
首先先从枚举顺序上来:显然,当我们做数独时,总是从能直接确定的开始,之后是有2种可能的……
因此,我们可以受到启发-从可能性最少的开始枚举!
同时,还有一个任务是总分最大……分数的上界是很好算的(贪心算当前格子最大的可能取的数字,乘以权重)。这样就可以使用A*算法。
完整代码如下:
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
struct node
{
int a[9][9];
int h,g,filled;
bool operator<(const node & a) const
{
return (h + g < a.h + a.g);
}
};
struct point
{
int x,y;
};
priority_queue<node> q;
bool valid[10];
int v[9][9];
bool ok[9][9][10];
node init;
inline int max(int x,int y)
{
if (x > y) return x;
return y;
}
inline int abs(int x)
{
if (x > 0) return x;
return -x;
}
inline int score(int x,int y)
{
return (10 - max(abs(4-x),abs(4-y)));
}
point findMin(const node & n)
{
int min = 99;
point minp;
point error;
error.x = -1;
error.y = -1;
memset(v,0,sizeof v);
memset(ok,0,sizeof ok);
for (int i = 0;i < 9;++i)
{
for (int j = 0;j < 9;++j)
{
if (n.a[i][j] != 0) continue;
memset(valid,true,sizeof valid);
for (int k = 0;k < 9;++k)
{
valid[n.a[i][k]] = false;
valid[n.a[k][j]] = false;
}
int bx = i/3;
int by = j/3;
for (int k = 3*bx;k < 3*bx+3;++k)
{
for (int l = 3*by;l < 3*by+3;++l)
{
valid[n.a[k][l]] = false;
}
}
int count = 0;
for (int k = 1;k < 10;++k)
{
if (valid[k])
{
count++;
v[i][j]++;
ok[i][j][k] = true;
}
}
if (count == 0)
{
return error;
}
else if (count < min)
{
min = count;
minp.x = i;
minp.y = j;
}
}
}
return minp;
}
int heuristic(const node & n)
{
int ans = 0;
for (int i = 0;i < 9;++i)
{
for (int j = 0;j < 9;++j)
{
if (n.a[i][j] == 0)
{
for (int k = 9;k >= 1;--k)
{
if (ok[i][j][k])
{
ans += score(i,j) * k;
break;
}
}
}
}
}
return ans;
}
void aStar()
{
q.push(init);
point first;
while (!q.empty())
{
node temp = q.top();
node t2;
q.pop();
first = findMin(temp);
if (first.x != -1)
{
for (int k = 1;k <= 9;++k)
{
if (ok[first.x][first.y][k])
{
for (int l = 0;l < 9;++l)
{
for (int m = 0;m < 9;++m)
{
t2.a[l][m] = temp.a[l][m];
}
}
t2.a[first.x][first.y] = k;
t2.g = temp.g + score(first.x, first.y) * k;
t2.h = heuristic(t2);
t2.filled = temp.filled + 1;
if (t2.filled == 81)
{
cout << t2.g << endl;
return;
}
q.push(t2);
}
}
}
}
cout << -1 << endl;
}
int main(int argc, const char * argv[])
{
for (int i = 0;i < 9;++i)
{
for (int j = 0;j < 9;++j)
{
cin >> init.a[i][j];
if (init.a[i][j] != 0)
{
init.g += score(i,j) * init.a[i][j];
init.filled++;
}
}
}
findMin(init);
init.h = heuristic(init);
aStar();
return 0;
}