poj3074, DLX解数独源代码
2013年6月26日 20:49
#include <cstdio> #include <iostream> #include <cstring> #include <sstream> #include <cstdlib> #include <cmath> #include <ctime> #include <vector> #include <set> #include <queue> #include <map> #include <iterator> #include <algorithm> using namespace std; int const N = 3; int PN = N * N, QN = PN * PN; /***最大行***/ #define MAXROW 1001 /***最大列***/ #define MAXCOL 1001 struct DancingLinksNode { /***结点所在的行列位置***/ int r, c; /***结点的上下左右结点指针***/ DancingLinksNode *U, *D, *L, *R; }; /****备用结点****/ DancingLinksNode node[MAXROW * 101]; /****行头****/ DancingLinksNode row[MAXROW]; /****列头****/ DancingLinksNode col[MAXCOL]; /****表头****/ DancingLinksNode head; /****使用了多少结点****/ int cnt; /****列含有多少个域****/ int size[MAXCOL]; /****表的行与列变量****/ int m, n; /****选择的行****/ int choice[MAXROW]; /****初始化,r, c分别表示表的大小***/ void init(int r, int c) { /****将可以使用的结点设为第一个****/ cnt = 0; /****head结点的r,c分别表示表的大小,以备查****/ head.r = r; head.c = c; /****初始化head结点****/ head.L = head.R = head.U = head.D = &head; /***初始化列头***/ for(int i = 0; i < c; ++i) { col[i].r = r; col[i].c = i; col[i].L = head.L; col[i].R = &head; col[i].L->R = col[i].R->L = &col[i]; col[i].U = col[i].D = &col[i]; size[i] = 0; } /***初始化行头,在删除的时候,如果碰到row[i].c == c的情形应当被跳过***/ for(int i = r - 1; i > -1; --i) { row[i].r = i; row[i].c = c; row[i].U = head.U; row[i].D = &head; row[i].U->D = row[i].D->U = &row[i]; row[i].L = row[i].R = &row[i]; } } /****增加一个结点,在原表中的位置为r行,c列***/ inline void addNode(int r, int c) { /****找一个未曾使用的结点****/ DancingLinksNode *ptr = &node[cnt++]; /****设置结点的行列号****/ ptr->r = r; ptr->c = c; /****将结点加入双向链表中****/ ptr->L = row[r].L; ptr->R = &row[r]; ptr->L->R = ptr->R->L = ptr; ptr->U = col[c].U; ptr->D = &col[c]; ptr->U->D = ptr->D->U = ptr; /****将size域加1****/ ++size[c]; } /****删除ptr所指向的结点的左右方向****/ inline void delLR(DancingLinksNode * ptr) { ptr->L->R = ptr->R; ptr->R->L = ptr->L; } /****删除ptr所指向的结点的上下方向****/ inline void delUD(DancingLinksNode * ptr) { ptr->U->D = ptr->D; ptr->D->U = ptr->U; } /****重置ptr所指向的结点的左右方向****/ inline void resumeLR(DancingLinksNode * ptr) { ptr->L->R = ptr->R->L = ptr; } /****重置ptr所指向的结点的上下方向****/ inline void resumeUD(DancingLinksNode * ptr) { ptr->U->D = ptr->D->U = ptr; } /****覆盖第c例***/ inline void cover(int c) { /**** c == n 表示头****/ if(c == n) { return; } /****删除表头****/ delLR(&col[c]); DancingLinksNode *R, *C; for(C = col[c].D; C != (&col[c]); C = C->D) { if(C->c == n) continue; for(R = C->L; R != C; R = R->L){ if(R->c == n) continue; --size[R->c]; delUD(R); } delLR(C); } } /****重置第c列****/ inline void resume(int c) { if(c == n) return; DancingLinksNode *R, *C; for(C = col[c].U; C != (&col[c]); C = C->U) { if(C->c == n) continue; resumeLR(C); for(R = C->R; R != C; R = R->R) { if(R->c == n) continue; ++size[R->c]; resumeUD(R); } } /****把列头接进表头中****/ resumeLR(&col[c]); } /****搜索核心算法,k表示搜索层数****/ int search(int k = 0) { /***搜索成功,返回true***/ if(head.L == (&head)) { return k; } /***c表示下一个列对象位置,找一个分支数目最小的进行覆盖***/ int INF = (1<<30), c = -1; for(DancingLinksNode * ptr = head.L; ptr != (&head); ptr = ptr->L) { if(size[ptr->c] < INF) { INF = size[ptr->c]; c = ptr->c; } } /***覆盖第c列***/ cover(c); DancingLinksNode * ptr; for(ptr = col[c].D; ptr != (&col[c]); ptr = ptr->D) { DancingLinksNode *rc; ptr->R->L = ptr; choice[k] = ptr->r; for(rc = ptr->L; rc != ptr; rc = rc->L) { cover(rc->c); } ptr->R->L = ptr->L; int ans = search(k + 1); if(ans) { return ans; } ptr->L->R = ptr; for(rc = ptr->R; rc != ptr; rc = rc->R) { resume(rc->c); } ptr->L->R = ptr->R; } /***取消覆盖第c列***/ resume(c); return 0; } void addPoss(int i, int j) { int x = i / PN, y = i % PN; addNode(i * PN + j, i); addNode(i * PN + j, QN * 1+ x * PN + j); addNode(i * PN + j, QN * 2 + y * PN + j); addNode(i * PN + j, QN * 3 + (x / N * N + y / N) * PN + j); } int main(int argc, char** argv) { char s[100]; while(1) { scanf("%s", s); if(strcmp(s, "end") == 0) { break; } m = PN * QN, n = 4 * QN; init(m, n); for(int i = 0; i < QN; ++i) { if(s[i] == '.') { for(int j = 0; j < PN; ++j) addPoss(i, j); } else { addPoss(i, s[i] - '1'); } } search(); for(int i = 0; i < QN; i ++) { s[choice[i] / PN] = choice[i] % PN + '1'; } puts(s); } return 0; }