洛谷1074 靶形数独
原题链接
终究还是逃不过这题,真的懒得写爆搜。。
在某一行中填数时,可以使用链表以减少无用的遍历,即防止遍历到在该行已经填过的数字。
再开\(3\)个数组,一个记录改格是否填过数,一个记录这一列中哪些数已经存在,一个记录这个格子所在的九宫格里哪些数已经存在。
对于转成九宫格的下标,其实是有公式的,不过我比较懒,就直接用\(if\)判断了。
在搜到的格子分数相对较小的情况下,从小到大填数,相对较大则从大到小填。
而一个比较好优化就是先搜未知量少的行,能有效减少搜索树的枝叶。
另外,这题可以用二进制优化的数独,效率比单纯的爆搜要高,但我太菜了,不会。
#include<cstdio> #include<algorithm> using namespace std; const int N = 11; struct lt { int pre, suc; }; lt H[N][N]; struct dd { int id, s; }; dd nz[N]; bool v[N][N], vl[N][N], vg[4][4][N]; int a[N][N] = { {0}, {0, 6, 6, 6, 6, 6, 6, 6, 6, 6}, {0, 6, 7, 7, 7, 7, 7, 7, 7, 6}, {0, 6, 7, 8, 8, 8, 8, 8, 7, 6}, {0, 6, 7, 8, 9, 9, 9, 8, 7, 6}, {0, 6, 7, 8, 9, 10, 9, 8, 7, 6}, {0, 6, 7, 8, 9, 9, 9, 8, 7, 6}, {0, 6, 7, 8, 8, 8, 8, 8, 7, 6}, {0, 6, 7, 7, 7, 7, 7, 7, 7, 6}, {0, 6, 6, 6, 6, 6, 6, 6, 6, 6}, }, ans, s; inline int re() { int x = 0; char c = getchar(); bool p = 0; for (; c < '0' || c > '9'; c = getchar()) p |= c == '-'; for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0'; return p ? -x : x; } void dfs(int x, int y); inline int maxn(int x, int y) { return x > y ? x : y; } inline void del(int x, int y) { H[x][H[x][y].pre].suc = H[x][y].suc; H[x][H[x][y].suc].pre = H[x][y].pre; }//删除链表中的某个链节 inline void rec(int x, int y) { H[x][H[x][y].pre].suc = y; H[x][H[x][y].suc].pre = y; }//恢复链表中的某个链节 inline int ch(int x) { return x < 4 ? 1 : x > 6 ? 3 : 2; }//转为就九宫格的下标 bool comp(dd x, dd y) { return x.s > y.s; } void calc(int x, int y, int i, int xx) { if (vl[y][i] || vg[ch(x)][ch(y)][i]) return; v[x][y] = vl[y][i] = vg[ch(x)][ch(y)][i] = 1; del(x, i); s += i * a[x][y]; dfs(xx, y + 1); s -= i * a[x][y]; rec(x, i); v[x][y] = vl[y][i] = vg[ch(x)][ch(y)][i] = 0; } void dfs(int xx, int y) { if (y > 9) ++xx, y = 1; int i, x = nz[xx].id; if (x > 9) { ans = maxn(ans, s); return; } if (v[x][y]) { dfs(xx, y + 1); return; } if (a[x][y] < 9)//格子分数相对较小的情况下,从小到大填数 for (i = H[x][0].suc; i <= 9; i = H[x][i].suc) calc(x, y, i, xx); else//否则从大到小填 for (i = H[x][10].pre; i; i = H[x][i].pre) calc(x, y, i, xx); } int main() { int i, j, x; for (i = 1; i <= 9; i++) for (j = H[i][0].suc = 1, H[i][10].pre = 9; j <= 9; j++) H[i][j].pre = j - 1, H[i][j].suc = j + 1;//初始化链表 for (i = 1, nz[10].id = 10; i <= 9; i++) for (j = 1, nz[i].id = i; j <= 9; j++) { x = re(); if (!x) continue; nz[i].s++; s += x * a[i][j]; del(i, x); if (vl[j][x] || vg[ch(i)][ch(j)][x])//如果输入的数独就不合法,直接输出-1 return printf("-1"), 0; v[i][j] = vl[j][x] = vg[ch(i)][ch(j)][x] = 1; } sort(nz + 1, nz + 10, comp);//按未知量的多少对行的搜索顺序进行排序 dfs(1, 1); printf("%d", ans ? ans : -1); return 0; } posted on 2019-02-17 15:21 Iowa_Battleship 阅读(160) 评论(0) 收藏 举报
浙公网安备 33010602011771号