zoukankan      html  css  js  c++  java
  • 题解 P1074 【靶形数独 】

    题目链接:Link

    Solution

    来一篇通俗点的DLX的题解。

    有关DLX的讲解:

    针对本题的一些细节详见注释。

    code:

    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int maxn=81*4+5;
    const int maxnode=9*9*9*4*4+5;
    const int Slot=0,Row=1,Col=2,Sub=3;//四种类型的覆盖任务编号
    const int p[9][9]=//预处理权值
    {
    {6,6,6,6,6,6,6,6,6},
    {6,7,7,7,7,7,7,7,6},
    {6,7,8,8,8,8,8,7,6},
    {6,7,8,9,9,9,8,7,6},
    {6,7,8,9,10,9,8,7,6},
    {6,7,8,9,9,9,8,7,6},
    {6,7,8,8,8,8,8,7,6},
    {6,7,7,7,7,7,7,7,6},
    {6,6,6,6,6,6,6,6,6}
    };
    inline int encode(int a,int b,int c) { return a*81+b*9+c+1; }//统一编码函数
    inline void decode(int code,int &a,int &b,int &c)
    {//统一解码函数
    	code--;
    	c=code%9; code/=9;
    	b=code%9; code/=9;
    	a=code;
    }
    int res=-1,mp[9][9];//答案和输入数据
    struct DLX
    {
    	int n,sz;
    	int s[maxn];
    	int row[maxnode],col[maxnode];
    	int L[maxnode],R[maxnode],U[maxnode],D[maxnode];
    	void init(int n)//初始化,0为超级节点,1~n为每列的虚拟节点
    	{
    		this->n=n;
    		sz=n+1;
    		memset(s,0,sizeof(s));
    		for(int i=0;i<=n;i++) { U[i]=i; D[i]=i; L[i]=i-1; R[i]=i+1; }
    		R[n]=0; L[0]=n;
    	}
    	void addNodes(int r,const vector<int> &columns)
    	{//在第最后一行添加第r种方案这些节点
    		int first=sz,c_sz=columns.size();
    		for(int i=0;i<c_sz;i++)
    		{
    			int c=columns[i];
    			L[sz]=sz-1; R[sz]=sz+1; D[sz]=c; U[sz]=U[c];
    			D[U[c]]=sz; U[c]=sz;
    			row[sz]=r; col[sz]=c;
    			s[c]++;sz++;
    		}
    		R[sz-1]=first; L[first]=sz-1;
    	}
    	#define For(i,A,s) for(int i=A[s];i!=s;i=A[i])
    	void remove(int c)//覆盖第c个目标
    	{
    		L[R[c]]=L[c];
    		R[L[c]]=R[c];
    		For(i,D,c) For(j,R,i) { U[D[j]]=U[j]; D[U[j]]=D[j]; --s[col[j]]; }//撕开所有相关节点
    	}
    	void restore(int c)
    	{//复原,切记顺序和原来相反
    		For(i,U,c) For(j,L,i) { ++s[col[j]]; U[D[j]]=j; D[U[j]]=j; }
    		L[R[c]]=c;
    		R[L[c]]=c;
    	}
    	bool dfs(int val)
    	{
    		if(R[0]==0) { res=max(res,val); return true; }
    		int c=R[0],flag=false;
    		For(i,R,0) if(s[i]<s[c]) c=i;
    		remove(c);
    		For(i,D,c)
    		{
    			For(j,R,i) remove(col[j]);//为了确保只覆盖一次
    			int nr,nc,nv;
    			decode(row[i],nr,nc,nv);
    			if(dfs(val+p[nr][nc]*(nv+1))) flag=true;
    			For(j,L,i) restore(col[j]);//回溯
    		}
    		restore(c);//回溯
    		return flag;
    	}
    	#undef For
    };
    DLX solver;
    #define For(i,a,b) for(int i=(a);i<=(b);i++)
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	For(r,0,8) For(c,0,8) scanf("%d",&mp[r][c]);
    	solver.init(9*9*4);
    	For(r,0,8) For(c,0,8) For(v,0,8)
    		if(mp[r][c]==0||mp[r][c]==v+1)
    		{//转换成DLX中的目标
    			vector<int> cols;
    			cols.push_back(encode(Slot,r,c));
    			cols.push_back(encode(Row,r,v));
    			cols.push_back(encode(Col,c,v));
    			cols.push_back(encode(Sub,(r/3)*3+c/3,v));
    			solver.addNodes(encode(r,c,v),cols);
    		}
    	solver.dfs(0);
    	printf("%d
    ",res);
    	return 0;
    }
    

    PS:其实这题和UVA1309很像,有兴趣的同学可以去看看UVA1309题解 UVA1309 【Sudoku】


    致谢:

    • DLX的模板来自于刘汝佳大神的《算法竞赛训练指南》
    • @grenet大神
  • 相关阅读:
    什么是IOC
    spring的作用
    什么是spring框架?
    72
    71
    70
    69
    68
    67
    66
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11379512.html
Copyright © 2011-2022 走看看