hdu 4069 垃圾數獨
阿新 • • 發佈:2018-10-14
ase ring %d lin iostream 結點 初始 class 集合
首先dfs給每個格子分一個大的區塊
其次套板子就a
我一開始直接在選取行的時候填數獨,發現超時
我這一行也就4個元素,找到 x <= 81 的列計算元素位置,81 < x <= 162 的列計算是什麽數字
這就超時了?
後來還是記錄每一行的代表的 行和列 和 數字
選區行的時候記錄選取的行
最後矩陣為空的時候 一起填入數獨
#include <iostream> #include <cstring> #include <cstdio> using namespace std; //精確覆蓋問題的定義:給定一個由0-1組成的矩陣,是否能找到一個行的集合,使得集合中每一列都恰好包含一個1const int MN = 1005;//最大行數 const int MM = 1005;//最大列數 const int MNN = 1e5+5; //最大點數 int pl; int anss[15][15]; struct node { int i,j,val; }; node p[9*9*9+10]; struct DLX { int n, m, si;//n行數m列數si目前有的節點數 //十字鏈表組成部分 int U[MNN], D[MNN], L[MNN], R[MNN], Row[MNN], Col[MNN]; //第i個結點的U向上指針D下L左R右,所在位置Row行Col列int H[MN], S[MM]; //記錄行的選擇情況和列的覆蓋情況 int ansd, ans[MN]; int k = 0; void init(int _n, int _m) //初始化空表 { n = _n; m = _m; k = 0; 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; si = m; //目前用了前0~m個結點 memset(S, 0, sizeof(S)); memset(H, -1, sizeof(H)); } void link(int r, int c) //插入點(r,c) { ++S[Col[++si] = c]; //si++;Col[si]=c;S[c]++; Row[si] = r;//si該結點的行數為r D[si] = D[c];//向下指向c的下面的第一個結點 U[D[c]] = si;//c的下面的第一個結點的上面為si U[si] = c;//si的上面為列指針 D[c] = si;//列指針指向的第一個該列中的元素設為si if (H[r]<0)//如果第r行沒有元素 H[r] = L[si] = R[si] = si; else { R[si] = R[H[r]];//si的右邊為行指針所指的右邊第一個元素 L[R[H[r]]] = si;//行指針所指的右邊第一個元素的左側為si L[si] = H[r];//si的左側為行指針 R[H[r]] = si;//行指針的右側為si } } void rm(int c) //列表中刪掉c列 { L[R[c]] = L[c];//表頭操作 //c列頭指針的右邊的元素的左側指向c列頭指針左邊的元素 R[L[c]] = R[c];//c列頭指針的左邊的元素的右側指向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[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])//枚舉該列元素所在的行 ++S[Col[U[D[j]] = D[U[j]] = j]];//D[U[j]]=j;U[D[j]]=j;S[Col[j]]++; L[R[c]] = R[L[c]] = c;//c列頭指針左右相連 } bool dance(int d) //選取了d行 { if (ansd != -1 && ansd < d)return 0; if (R[0] == 0)//全部覆蓋了 { k++; //全覆蓋了之後的操作 if(ansd==-1)ansd = d; else if (d < ansd) ansd = d; /*memcpy(fina,anss,sizeof(anss)); for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) printf("%d",anss[i][j]); printf("\n"); }*/ for(int i = 0; i < ansd; ++i) { anss[p[ans[i]].i][p[ans[i]].j] = p[ans[i]].val; } return 1; } int c = R[0];//表頭結點指向的第一個列 for (int i = R[0]; i != 0; i = R[i])//枚舉列頭指針 if (S[i]<S[c])//找到列中元素個數最少的 c = i; rm(c);//將該列刪去 for (int i = D[c]; i != c; i = D[i]) { ans[d] = Row[i]; for (int j = R[i]; j != i; j = R[j]) rm(Col[j]);//將該列的某個元素的行上的元素所在的列都刪去 dance(d + 1); if(k == 2 ) return 1; for (int j = L[i]; j != i; j = L[j]) resume(Col[j]); } resume(c); return 0; } }; int s[20][20]; int kua[20][20]; int arr[20][20]; int dx[4] = {0,1,0,-1}; int dy[4] = {-1,0,1,0}; int fc[4] = {128,64,32,16}; DLX di; void dfs(int x,int y,int cnt); int main() { int t,ppap = 1; scanf("%d",&t); while(ppap <= t) { memset(anss,0,sizeof(anss)); for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) { scanf("%d",s[i]+j); } } int cnt = 1; memset(kua,0,sizeof(kua)); for(int i = 0; i < 9; ++i) for(int j = 0; j < 9; ++j) { if(kua[i][j] == 0) { kua[i][j] = cnt; dfs(i,j,cnt++); } } /* for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) printf("%d ",arr[i][j]); printf("\n"); } */ //---------------------------- di.init(9*9*9,9*9*4); for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) { //cout << s[cnt]; if(arr[i][j] == 0) { for(int d = 1; d <= 9; ++d) { di.link(i*9*9+j*9+d,i*9+j+1); di.link(i*9*9+j*9+d,i*9+d+81); di.link(i*9*9+j*9+d,j*9+d+162); di.link(i*9*9+j*9+d,(kua[i][j]-1)*9+d+243); p[i*9*9+j*9+d].i = i; p[i*9*9+j*9+d].j = j; p[i*9*9+j*9+d].val = d; } } else { int d = arr[i][j]; di.link(i*9*9+j*9+d,i*9+j+1); di.link(i*9*9+j*9+d,i*9+d+81); di.link(i*9*9+j*9+d,j*9+d+162); di.link(i*9*9+j*9+d,(kua[i][j]-1)*9+d+243); p[i*9*9+j*9+d].i = i; p[i*9*9+j*9+d].j = j; p[i*9*9+j*9+d].val = d; } } } di.ansd = -1; di.dance(0); printf("Case %d:\n",ppap++); if(di.ansd == -1) { printf("No solution\n"); continue; } if(di.k != 1) { printf("Multiple Solutions\n"); continue; } /*for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) printf("%d",anss[i][j]); printf("\n"); }*/ for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) { printf("%d",anss[i][j]); } printf("\n"); } } } void dfs(int x,int y,int cnt) { int k = s[x][y]; //cout << x << y << " " << s[x][y]<< endl; int xx,yy; for(int i = 0; i < 4; ++i) { xx = x + dx[i]; yy = y + dy[i]; if(k >= fc[i]) { k-=fc[i]; continue; } if(kua[xx][yy] == 0){ kua[xx][yy] = cnt; dfs(xx,yy,cnt); } } arr[x][y] = k; }
hdu 4069 垃圾數獨