zoukankan      html  css  js  c++  java
  • poj3074-Sodoku

    解数独。

    分析

    考虑如何把数独解合法的条件转化为经典的01精确覆盖:

    • 每个格子只能填一个数,1-9
    • 每一列刚好填了1-9
    • 每一行刚好填了1-9
    • 每个九宫格刚好填了1-9

    也就是说,每个格子,列,行,九宫格都需要被一个数覆盖,且不能重复覆盖。

    精确覆盖的一个很巧妙的,也很常用的建矩阵方法,是把条件拆开,把每一个填入也拆成对四种条件的贡献。

    也就是说,我们建一个729*324的矩阵。所有的行表示在((x,y))填入(k),前81列表示每个格子被覆盖,后面的各81列分别表示每一列,一行,九宫格被覆盖,那么这就是一个精确覆盖问题了——每次填入一个数,可以对应地在四个规则中产生贡献。

    如果已经给到有数了,那么就((x,y))就只能填入规定的那个(k),否则可以填1-9。

    代码

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=10*10*10;
    const int maxm=10*10*5;
    const int maxl=10*10;
    const int maxp=maxn*maxm;
    bool a[maxn][maxm];
    char s[maxl];
    int ans[10][10];
    struct node {
    	int l,r,u,d,row,col;
    };
    int id(int x,int y) {
    	return (x-1)*9+y;
    }
    int hang(int x,int k) {
    	return 81+(x-1)*9+k;
    }
    int lie(int y,int k) {
    	return 162+(y-1)*9+k;
    }
    int bel(int x,int y) {
    	return ((x-1)/3)*3+(y-1)/3+1;
    }
    int gong(int x,int y,int k) {
    	return 243+(bel(x,y)-1)*9+k;
    }
    int choose(int x,int y,int k) {
    	return (id(x,y)-1)*9+k;
    }
    void ANS(int row) {
    	int k=(row-1)%9+1;
    	row-=k;
    	int d=row/9+1;
    	int y=(d-1)%9+1;
    	int x=(d-y)/9+1;
    	ans[x][y]=k;
    }
    struct DLX {
    	node p[maxp];
    	int tot,last[maxm],size[maxm];
    	void clear(int n) {
    		tot=n;
    		memset(p,0,sizeof p),memset(last,0,sizeof last),memset(size,0,sizeof size);
    		p[0]=(node){n,1,0,0,0,0};
    		for (int i=1;i<=n;++i) p[i]=(node){i-1,i+1,i,i,0,i},last[i]=i;
    		p[n].r=0;
    	}
    	void build(int row,int c[],int len) {
    		if (!len) return;
    		p[++tot]=(node){tot,tot,last[c[1]],p[last[c[1]]].d,row,c[1]};
    		p[p[tot].u].d=p[p[tot].d].u=last[c[1]]=tot;
    		++size[p[tot].col];
    		for (int i=2;i<=len;++i) {
    			int x=c[i];
    			p[++tot]=(node){tot-1,p[tot-1].r,last[x],p[last[x]].d,row,x};
    			p[p[tot].l].r=p[p[tot].r].l=p[p[tot].d].u=p[p[tot].u].d=last[x]=tot;
    			++size[p[tot].col];
    		}
    	}
    	void del(int c) {
    		p[p[c].l].r=p[c].r,p[p[c].r].l=p[c].l;
    		for (int i=p[c].d;i!=c;i=p[i].d) 
    			for (int j=p[i].r;j!=i;j=p[j].r) 
    				p[p[j].u].d=p[j].d,p[p[j].d].u=p[j].u,--size[p[j].col];
    	}
    	void back(int c) {
    		p[p[c].l].r=p[p[c].r].l=c;
    		for (int i=p[c].u;i!=c;i=p[i].u) 
    			for (int j=p[i].l;j!=i;j=p[j].l) 
    				p[p[j].u].d=p[p[j].d].u=j,++size[p[j].col];
    	}
    	bool dance() {
    		if (!p[0].r) return true;
    		int first=p[0].r;
    		for (int i=p[0].r;i;i=p[i].r) if (size[i]<size[first]) first=i;
    		if (p[first].d==first) return false;
    		del(first);
    		for (int i=p[first].d;i!=first;i=p[i].d) {
    			for (int j=p[i].r;j!=i;j=p[j].r) del(p[j].col);
    			ANS(p[i].row);
    			if (dance()) return true;
    			for (int j=p[i].l;j!=i;j=p[j].l) back(p[j].col);
    		}
    		back(first);
    		return false;
    	}
    } dlx;
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	while (~scanf("%s",s+1)) {
    		dlx.clear(324);
    		memset(a,0,sizeof a),memset(ans,0,sizeof ans);
    		if (s[1]=='e') break;
    		for (int i=1,k=0;i<=9;++i) for (int j=1;j<=9;++j) {
    			int x=(s[++k]=='.'?0:s[k]-'0'),st=(x?x:1),ed=(x?x:9);
    			ans[i][j]=x;
    			for (int k=st;k<=ed;++k) {
    				int cho=choose(i,j,k);
    				a[cho][id(i,j)]=a[cho][hang(i,k)]=a[cho][lie(j,k)]=a[cho][gong(i,j,k)]=true;
    			}
    		}
    		for (int i=1;i<=729;++i) {
    			static int c[maxm];
    			int tot=0;
    			for (int j=1;j<=324;++j) if (a[i][j]) c[++tot]=j;
    			dlx.build(i,c,tot);
    		}
    		dlx.dance();
    		for (int i=1;i<=9;++i) for (int j=1;j<=9;++j) printf("%d",ans[i][j]);
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    fedora中使用 mariadb数据库建库和建表-- mariadb数据库服务无法启动?
    我在linux中使用的vundle 和 vimrc配置
    vim的加密和解密?
    gvim写html代码时如何快速地跳转到一个标签的结束位置: 终极插件: matchit.vim
    HTML5+CSS3整体回顾
    HTML5无刷新修改URL
    使用ab对nginx进行压力测试
    nginx php-fpm 输出php错误日志
    如何正确配置Nginx+PHP
    关于Nginx的一些优化(突破十万并发)
  • 原文地址:https://www.cnblogs.com/owenyu/p/6741069.html
Copyright © 2011-2022 走看看