hdu 4069 垃圾数独
Posted mltang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 4069 垃圾数独相关的知识,希望对你有一定的参考价值。
首先dfs给每个格子分一个大的区块
其次套板子就a
我一开始直接在选取行的时候填数独,发现超时
我这一行也就4个元素,找到 x <= 81 的列计算元素位置,81 < x <= 162 的列计算是什么数字
这就超时了?
后来还是记录每一行的代表的 行和列 和 数字
选区行的时候记录选取的行
最后矩阵为空的时候 一起填入数独
#include <iostream> #include <cstring> #include <cstdio> using namespace std; //精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 const 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(" "); }*/ 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(" "); } */ //---------------------------- 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: ",ppap++); if(di.ansd == -1) { printf("No solution "); continue; } if(di.k != 1) { printf("Multiple Solutions "); continue; } /*for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) printf("%d",anss[i][j]); printf(" "); }*/ for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) { printf("%d",anss[i][j]); } printf(" "); } } } 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 垃圾数独的主要内容,如果未能解决你的问题,请参考以下文章