poj 3074

记录一下学习DLX的一些碎碎念吧。

其实dacing links 并不是一个算法,而是一个数据结构,这个算法的名字叫做x算法,其实,DLX本身也是回溯法的一种,它的优点在于可以非常快速地完成点的删除和复原。

这个数据结构是基于交叉十字链表实现的,用这个结构很自然,因为不旦要对行进行操作还要对列操作。

删除元素时,列元素的删除是因为不需要再考虑了,行元素的删除是因为不能考虑。

X算法使基于排除法的。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF = 0x7fffffff;
const int NN = 350;
const int MM = 750;

int n,m;
int cntc[NN];
int L[NN*MM],R[NN*MM],U[NN*MM],D[NN*MM];
int C[NN*MM];
int head;
int mx[MM][NN]; 
int O[MM],idx; 
int ans[10][10];

void remove(int c)
{
    int i,j;
    L[R[c]] = L[c];
    R[L[c]] = R[c];
    for(i = D[c]; i != c; i = D[i])
    {
        for(j = R[i]; j != i; j = R[j])
        {
            U[D[j]] = U[j];
            D[U[j]] = D[j];
            cntc[C[j]]--;
        }
    }
}

void resume(int c)
{
    int i,j;
    R[L[c]] = c;
    L[R[c]] = c;
    for(i = D[c]; i != c; i = D[i])
    {
        for(j = R[i]; j != i; j = R[j])
        {
            U[D[j]] = j;
            D[U[j]] = j;
            cntc[C[j]]++;
        }
    }
}

bool dfs()
{
    int i,j,c;
    if(R[head] == head)
        return true;
    int min = INF;
    for(i = R[head]; i != head; i = R[i])
    {
        if(cntc[i] < min)
        {
            min = cntc[i];
            c = i;
        }
    }
    remove(c);
    for(i = D[c]; i != c; i = D[i])
    {
        O[idx++] = (i-1)/n;
        for(j = R[i]; j != i; j = R[j])
            remove(C[j]);      
        if(dfs())
            return true;
        for(j = L[i]; j != i; j = L[j])
            resume(C[j]);
        idx--;
    }
    resume(c);
    return false;
}

bool build()
{
    int i,j,now,pre,first;
    idx = head = 0;
    for(i = 0; i < n; i++)
    {
        R[i] = i+1;
        L[i+1] = i;
    }
    R[n] = 0;
    L[0] = n;
    for(j = 1; j <= n; j++)
    {
        pre = j;
        cntc[j] = 0;
        for(i = 1; i <= m; i++)
        {
            if(mx[i][j])
            {
                cntc[j]++;
                now = i*n+j;
                C[now] = j;
                D[pre] = now;
                U[now] = pre;
                pre = now;
            }
        }
        U[j] = pre;
        D[pre] = j;
        if(cntc[j] == 0)
            return false;
    }
    for(i = 1; i <= m; i++)
    {
        pre = first = -1;
        for(j = 1; j <= n; j++)
        {
            if(mx[i][j])
            {
                now = i*n+j;
                if(pre == -1)
                    first = now;
                else
                {
                    R[pre] = now;
                    L[now] = pre;
                }
                pre = now;
            }
        }
        if(first != -1)
        {
            R[pre] = first;
            L[first] = pre;
        }
    }
    return true;
}

int T;

void print()
{
    int i,j;
    int x,y,k;
    for(i = 0; i < idx; i++)
    {
        int r = O[i];
        k = r%9;
        if(k==0) k = 9;
        int num = (r - k)/9 + 1;
        y = num%9;
        if(y == 0) y = 9;
        x = (num-y)/9 + 1;
        ans[x][y] = k;
    }
    if(idx == 0)
        printf("impossible\n");
    else
    {
        for(i = 1; i <= 9; i++)
        {
            for(j = 1; j <= 9; j++)
                printf("%d",ans[i][j]);
        }
        cout<<endl;
    }
}

int map[MM][NN];
string str;
void readdata()
{
    char ch;
    int ind=0;
    for(int i = 1; i <= 9; i++)
        for(int j = 1; j <= 9; j++)
          {
            ch=str[ind++];
            if(ch=='.')
            map[i][j]=0;
            else
            map[i][j]=ch-'0';
          }
}

int main()
{
    int i,j,k;
    int cases;
    char cao[12];
    char s[12][12];
    while(1)
    {
        cin>>str;
        if(str=="end")break;
        memset(mx,0,sizeof(mx));
        readdata();
        for(i = 1; i <= 9; i++)
        {
            for(j = 1; j <= 9; j++)
             {
                int t = (i-1)*9 + j;
                if(map[i][j] == 0)
                {
                    for(k = 1; k <= 9; k++)
                    {
                        mx[9*(t-1)+k][t] = 1;            
                        mx[9*(t-1)+k][81+(i-1)*9+k] = 1;  
                        mx[9*(t-1)+k][162+(j-1)*9+k] = 1;  
                        mx[9*(t-1)+k][243+((i-1)/3*3+(j+2)/3-1)*9+k] = 1;  
                    }
                }
                else
                {
                    k = map[i][j];
                    mx[9*(t-1)+k][t] = 1;
                    mx[9*(t-1)+k][81+(i-1)*9+k] = 1; 
                    mx[9*(t-1)+k][162+(j-1)*9+k] = 1; 
                    mx[9*(t-1)+k][243+((i-1)/3*3+(j+2)/3-1)*9+k] = 1;
                }
            }
        }
        n = 324;
        m = 729;
        build();
        dfs();
        print();
    }
    return 0;
}

为了准备四省赛,感觉自己需要写一个做数独的板子出来,于是就又做了一遍,注释也加得想当详细

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;

const int inf = 0x3f3f3f3f;
const int M = 750;
const int N = 400;

struct DLX{
	int D[M * N], U[M * N], L[M * N], R[M * N], col[M * N], row[M * N];
	int H[M], S[N];
	int m, n, id;
	int ansd;
	int ans[1010 * 4];
	
	void init(int _m, int _n){
		m = _m;
		n = _n;
		for(int i = 0; i <= n; i ++){
			L[i] = i - 1;
			R[i] = i + 1;
			U[i] = D[i] = i;
			S[i] = 0;
		}
		id = n;
		L[0] = n;
		R[n] = 0;
		for(int i = 1; i <= m; i ++)
			H[i] = -1;
	}
	void link(int r, int c){
		++ S[col[++ id] = c];
		row[id] = r;
		D[id] = D[c], U[D[c]] = id;
		D[c] = id, U[id] = c;
		if(H[r] == -1)
			H[r] = L[id] = R[id] = id;
		else{
			R[id] = R[H[r]], L[R[H[r]]] = id;
			L[id] = H[r], R[H[r]] = id;
		}
	}
	void remove(int 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]){
				D[U[j]] = D[j];
				U[D[j]] = U[j];
				S[col[j]] --;
			}
		}
	}
	void resume(int c){
		for(int i = U[c]; i != c; i = U[i]){
			for(int j = L[i]; j != i; j = L[j]){
				D[U[j]] = U[D[j]] = j;
				S[col[j]] ++;
			}
		}
		L[R[c]] = R[L[c]] = c;
	}
	bool dance(int d)  
    {  
        if(R[0] == 0){  
            ansd = d;  
            return true;  
        }  
        int c = R[0];  
        //一个优化 找到列中包含1最多的列 因为这样有助于减少递归深度(很显然1多了 删掉的行也多 矩阵缩小得就快)  
        for(int i = R[0]; i != 0; i = R[i]){  
            if(S[i] < S[c])  
                c = i;  
        }  
        remove(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]) remove(col[j]);  
            if(dance(d + 1)) return true;  
            for(int j = L[i]; j != i; j = L[j]) resume(col[j]);  
        }  
        resume(c);  
        return false;  
    }  
}dlx;  
char s[100];  
int main(){  
    while(scanf("%s", s) != EOF){  
        if(strcmp(s, "end") == 0) break;  
        dlx. init(81 * 9, 81 * 4);  
        for(int i = 0; i < 9; i ++){  
            for(int j = 0; j < 9; j ++){  
                int x = i, y = j, z = (x / 3) * 3 + y / 3; //行,列,哪一宫   都是从0计数,因为k是从1开始的,所以可以完成从1~729的映射  
                int w = i * 9 + j;  //对应于字符串中的位置,同样也是0~80这81个数的原始状态 
                if(s[w] == '.'){  
                    for(int k = 1; k <= 9; k ++){  //对每一个i,j的组合都预留出9行,针对.或数字做不同变化 
                        dlx. link(w * 9 + k, w + 1);  
                        dlx. link(w * 9 + k, 81 + (x * 9) + k);  
                        dlx. link(w * 9 + k, 162 + (y * 9) + k);  
                        dlx. link(w * 9 + k, 243 + (z * 9) + k);  
                    }  
                }
				else{  
                    int t = s[w] - '0';  
                    dlx. link(w * 9 + t, w + 1);   //81grid 每个小格只能放一个数字  
                    dlx. link(w * 9 + t, 81 + x * 9 + t);//9row 每行数字k只能出现一次  
                    dlx. link(w * 9 + t, 162 + y * 9 + t);//9col  每列数字k只能出现一次  
                    dlx. link(w * 9 + t, 243 + z * 9 + t);//subgrid 每个3*3格子数字k只能出现一次  
                }  
            }  
        }  
        dlx. dance(0);  
        for(int i = 0; i < dlx. ansd; i ++){  
            int t = dlx.ans[i];  
            int a = (t - 1) / 9, b = (t - 1) % 9 + '1';  //除掉行中1~9这几个不同数的情况,剩下的就是行和列的组合。因为1~9是循环出现的,所以%9可以求出这一行代表着哪个数 
            s[(a / 9) * 9 + a % 9] = b;  //a/9 转换成对应的行    a%9  转换成对应的列 
        }
        puts(s);  
    }  
    return 0;  
}  

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/80042915