Dancing Links---- F
Today we play a squiggly sudoku, The objective is to fill a 9*9 grid with digits so that each column, each row, and each of the nine Connecting-sub-grids that compose the grid contains all of the digits from 1 to 9. Left figure is the puzzle and right figure is one solution.
Now, give you the information of the puzzle, please tell me is there no solution or multiple solution or one solution. Input The first line is a number T(1<=T<=2500), represents the number of case. The next T blocks follow each indicates a case. Each case contains nine lines, Each line contains nine integers. Each module number tells the information of the gird and is the sum of up to five integers: 0~9: ‘0’ means this gird is empty, ‘1’ - ‘9’ means the gird is already filled in. 16: wall to the up 32: wall to the right 64: wall to the down 128: wall to the left I promise there must be nine Connecting-sub-grids, and each contains nine girds. Output For each case, if there are Multiple Solutions or no solution just output “Multiple Solutions” or “No solution”. Else output the exclusive solution.(as shown in the sample output) Sample Input 3 144 18 112 208 80 25 54 144 48 135 38 147 80 121 128 97 130 32 137 32 160 144 114 167 208 0 32 192 100 160 160 208 96 183 192 101 209 80 39 192 86 48 136 80 114 152 48 226 144 112 160 160 149 48 128 0 112 166 215 96 160 128 41 128 39 153 32 209 80 101 136 35 192 96 200 67 80 112 208 68 96
144 48 144 81 81 16 53 144 48 128 96 224 144 48 128 103 128 38 163 208 80 0 37 224 209 0 32 135 48 176 192 64 112 176 192 104 192 101 128 89 80 82 32 150 48 149 48 224 208 16 48 224 192 33 128 0 114 176 135 0 80 112 169 137 32 148 32 192 96 176 144 32 192 96 193 64 80 80 96 192 96
144 88 48 217 16 16 80 112 176 224 176 129 48 128 40 208 16 37 145 32 128 96 196 96 176 136 32 192 32 227 176 144 80 96 192 32 176 192 80 98 160 145 80 48 224 128 48 144 80 96 224 183 128 48 128 36 224 144 51 144 32 128 105 131 64 112 136 32 192 36 224 176 224 208 80 64 64 116 192 83 96 Sample Output Case 1: 521439678 763895124 984527361 346182795 157964832 812743956 235678419 479216583 698351247 Case 2: No solution Case 3: Multiple Solutions
這道題就是dfs找聯通塊,原先做的那個數獨題是要求每一宮要求1~9的數,現在這個題是每一行,每一列和每一個聯通塊,其實都是一樣的。。。。 我wa的原因是:由於有多種解法,dlx搜尋的時候,找到一個解法的時候應該把這個解法存下來,要不然就被找下一個解法的時候就覆蓋了 題中每個數都代表在該點可走的方向,一共有15個數,分別是0,16,32,64,128,48,80,144,96,160,192,112,176,224,208。。。。 舉個例子,像80就有兩個方向可走,左和右
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #include<queue> using namespace std; typedef long long LL; const int inf = 0x3f3f3f3f; const double eps = 1e-8; const double PI = acos(-1); #define pb push_back #define mp make_pair #define fi first #define se second //最大行數 const int MN = 4100; //最大列數 const int MM = 1100; //最大點數 const int MNN = 16 * 16 * 16 * 4 + 100; struct DLX { //一共n行m列,s個節點 int n,m,s; //交叉十字連結串列組成部分 //第i個節點的上U下D左L右R,所在位置row行col列 int U[MNN],D[MNN],L[MNN],R[MNN],row[MNN],col[MNN]; //H陣列記錄行選擇指標,S陣列記錄覆蓋個數 int H[MN],S[MM]; //res記錄行個數,ans陣列記錄可行解 int res,ans[MN],flag,mm[MN]; //初始化空表 void init(int x,int y) { n = x,m = y; //其中0節點作為head節點,其他作為列首節點 for(int i = 0;i <= m;++i){ U[i] = D[i] = i; L[i] = i - 1; R[i] = i + 1; } R[m] = 0;L[0] = m; s = m; memset(S,0,sizeof(S)); memset(H,-1,sizeof(H)); } void Insert(int r,int c) { //cout << c << endl; //節點數加一,設定s節點所處位置,以及S列覆蓋個數加一 s++;row[s] = r;col[s] = c;S[c]++; //將s節點插入對應列中 D[s] = D[c];U[D[c]] = s; U[s] = c;D[c] = s; if(H[r] < 0){//如果該行沒有元素,H[r]標記該行起始節點 H[r] = L[s] = R[s] = s; }else{ //將該節點插入該行第一個節點後面 R[s] = R[H[r]]; L[R[H[r]]] = s; L[s] = H[r]; R[H[r]] = s; } } //精確覆蓋 void Remove(int c) { //刪除c列 L[R[c]] = L[c];R[L[c]] = R[c]; //刪除該列上的元素對應的行 for(int i = D[c];i != c;i = D[i]){//列舉該列元素 for(int j = R[i];j != i;j = R[j]){//列舉列的某個元素所在行遍歷 U[D[j]] = U[j]; D[U[j]] = D[j]; //將該列上的S陣列減一 --S[col[j]]; } } } void resume(int c) { //恢復c列 for(int i = U[c];i != c;i = U[i]){//列舉該列元素 for(int j = L[i];j != i;j = L[j]){ U[D[j]] = j;D[U[j]] = j; ++S[col[j]]; } } L[R[c]] = c;R[L[c]] = c; } void dance(int deep) { if(flag > 1) return ; //當矩陣為空時,說明找到一個可行解,演算法終止 // cout << "R:" << R[0] << endl; if(R[0] == 0){ memcpy(mm,ans,sizeof(ans)); res = deep; flag++; return ; } //找到節點數最少的列,列舉這列上的所有行 int c = R[0]; for(int i = R[0];i != 0;i = R[i]){ if(S[i] < S[c]){ c = i; } } //cout << c << endl; //刪除節點數最少的列 Remove(c); for(int i = D[c];i != c;i = D[i]){ //將行r放入當前解 ans[deep] = row[i]; //行上節點對應的列上進行刪除 for(int j = R[i];j != i;j = R[j]) Remove(col[j]); //進入下一層 dance(deep + 1); //對行上的節點對應的列進行恢復 for(int j = L[i];j != i;j = L[j]) resume(col[j]); } //恢復節點數最少列 resume(c); } //重複覆蓋 //將列與矩陣完全分開 void Remove1(int c) { for(int i = D[c];i != c;i = D[i]){ L[R[i]] = L[i]; R[L[i]] = R[i]; } } void resume1(int c) { for(int i = D[c];i != c;i = D[i]){ L[R[i]] = R[L[i]] = i; } } int vis[MNN]; //估價函式,模擬刪除列,H(),函式返回的是至少還需要多少行才能完成重複覆蓋 int A() { int dis = 0; for(int i = R[0];i != 0;i = R[i]) vis[i] = 0; for(int i = R[0];i != 0;i = R[i]){ if(!vis[i]){ dis++;vis[i] = 1; for(int j = D[i];j != i;j = D[j]){ for(int k = R[j];k != j;k = R[k]){ vis[col[k]] = 1; } } } } return dis; } void dfs(int deep) { if(res > 1) return ; if(!R[0]){ res++; return; } int c = R[0]; for(int i = R[0];i != 0;i = R[i]){ if(S[i] < S[c]){ c = i; } } for(int i = D[c];i != c;i = D[i]){ //每次將第i列其他節點刪除,只保留第i節點,為了找該行的節點 Remove1(i); //將列上的節點完全與矩陣脫離,只刪列首節點是不行的 for(int j = R[i];j != i;j = R[j]){ Remove1(j); } dfs(deep + 1); for(int j = L[i];j != i;j = L[j]){ resume1(j); } resume1(i); } } }dlx; const int N = 15; int col[5] = {-1,1,0,0}; int con[5] = {0,0,-1,1}; bool vis[N][N]; int a[N][N]; int b[N][N]; int c[N][N]; int cnt = 0; int ans[17] = {0,16,32,64,128,48,80,144,96,160,192,112,176,224,208}; map<int,vector<int> >mk; pair<pair<int,int>,int>ve[1005]; void dfs(int x,int y) { if(vis[x][y]) return ; vis[x][y] = true; for(int i = 0;i < 15;++i){ int tmp = a[x][y] - ans[i]; if(tmp >= 0 && tmp <= 9){ b[x][y] = tmp; c[x][y] = cnt; int len = mk[ans[i]].size(); for(int j = 0;j < len;++j){ int x1 = x + col[mk[ans[i]][j]],y1 = y + con[mk[ans[i]][j]]; if(x1 < 0 || y1 < 0 || x1 >= 9 || y1 >= 9 || vis[x1][y1]) continue; dfs(x1,y1); } break; } } } void init() { dlx.init(729,4 * 81); int k = 1; for(int i = 0;i < 9;++i){ for(int j = 0;j < 9;++j){ if(b[i][j]){ dlx.Insert(k,i * 9 + j + 1); dlx.Insert(k,81 + i * 9 + b[i][j]); dlx.Insert(k,2 * 81 + 9 * j + b[i][j]); dlx.Insert(k,3 * 81 + 9 * c[i][j] + b[i][j]); ve[k].fi = mp(i,j);ve[k].se = b[i][j]; k++; }else{ for(int x = 1;x <= 9;++x){ dlx.Insert(k,i * 9 + j + 1); dlx.Insert(k,81 + i * 9 + x); dlx.Insert(k,2 * 81 + 9 * j + x); dlx.Insert(k,3 * 81 + 9 * c[i][j] + x); ve[k].fi = mp(i,j);ve[k].se = x; k++; } } } } dlx.flag = dlx.res = 0; dlx.dance(0); if(dlx.flag == 0){ printf("No solution\n"); }else if(dlx.flag > 1){ printf("Multiple Solutions\n"); }else{ for(int i = 0;i < dlx.res;++i){ b[ve[dlx.mm[i]].fi.fi][ve[dlx.mm[i]].fi.se] = ve[dlx.mm[i]].se; } for(int i = 0;i < 9;++i){ for(int j = 0;j < 9;++j){ printf("%d",b[i][j]); } printf("\n"); } } } int main() { int t; mk[0].pb(0);mk[0].pb(1);mk[0].pb(2);mk[0].pb(3); mk[16].pb(2);mk[16].pb(1);mk[16].pb(3); mk[32].pb(0);mk[32].pb(1);mk[32].pb(2); mk[64].pb(0);mk[64].pb(2);mk[64].pb(3); mk[128].pb(0);mk[128].pb(1);mk[128].pb(3); mk[48].pb(1);mk[48].pb(2); mk[80].pb(2);mk[80].pb(3); mk[144].pb(1);mk[144].pb(3); mk[96].pb(0);mk[96].pb(2); mk[160].pb(0);mk[160].pb(1); mk[192].pb(0);mk[192].pb(3); mk[112].pb(2);mk[176].pb(1);mk[224].pb(0);mk[208].pb(3); scanf("%d",&t); int p = 0; while(t--) { p++; memset(vis,false,sizeof(vis)); for(int i = 0;i < 9;++i){ for(int j = 0;j < 9;++j){ scanf("%d",&a[i][j]); } } cnt = 0; for(int i = 0;i < 9;++i){ for(int j = 0;j < 9;++j){ if(!vis[i][j]){ dfs(i,j); cnt++; } } } printf("Case %d:\n",p); init(); } return 0; }