2082: 靶形数独

Time Limit: 2000 ms    Memory Limit: 131072 kB  
Judge type: Multi-cases (Detailed Mode - 20 cases)
Total Submit : 181 (41 users)   Accepted Submit : 25 (15 users)   Page View : 1792

Font Style: Aa Aa Aa
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z博士请教,Z 博士拿出了他最近发明的“靶形数独” ,作为这两个孩子比试的题目。
     靶形数独的方格同普通数独一样,在 9 格宽×9 格高的大九宫格中有 9 个 3 格宽×3 格高的小九宫格(用粗黑色线隔开的) 。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 1到 9 的数字。每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。 (如图)

上图具体的分值分布是:最里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8分,蓝色区域外面一圈(棕色区域)每个格子为 7分,最外面一圈(白色区域)每个格子为 6 分,如上图所示。
     比赛的要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法) ,而且要争取更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游戏规定,将以总分数的高低决出胜负。

由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能够得到的最高分数。

Input

一共 9 行。每行 9 个整数(每个数都在 0—9 的范围内) ,表示一个尚未填满的数独方格,未填的空格用“0”表示。每两个数字之间用一个空格隔开。

Output

输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1。

Sample Input

7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2

Sample Output

2829

Hint

40%的数据,数独中非 0数的个数不少于 30。
80%的数据,数独中非 0数的个数不少于 26。
100%的数据,数独中非 0 数的个数不少于 24。

Source

NOIP 2009 提高组

Best User : nehzilrz

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 1005
#define V 1020005
int U[V],D[V];
int L[V],R[V];
int C[V];
int H[N],S[N];
int mark[V];
int size,n,m,OK[N],flag;
int tnum[V];
void Link(int r,int c)
{
    S[c]++;C[size]=c;
    U[size]=U[c];D[U[c]]=size;
    D[size]=c;U[c]=size;
    if(H[r]==-1) H[r]=L[size]=R[size]=size;
    else
    {
        L[size]=L[H[r]];R[L[H[r]]]=size;
        R[size]=H[r];L[H[r]]=size;
    }
    mark[size]=r;
    size++;
}
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];
            S[C[j]]--;
        }
    }
}
void resume(int c)
{
    int i,j;
    for(i=U[c];i!=c;i=U[i])
    {
        for(j=L[i];j!=i;j=L[j])
        {
            U[D[j]]=j;D[U[j]]=j;
            S[C[j]]++;
        }
    }
    L[R[c]]=c;
    R[L[c]]=c;
}
int ans;
int fen[100],x[N],y[N];//输出所有解用的
void Dance(int k)
{
    int i,j,Min,c;
    if(!R[0])
    {
        flag=1;//标记有解
        //sort(OK, OK+k);
        int cnt=0;
        for(int i=0;i<k;i++)
        {
            int t=mark[OK[i]];
            int pos=x[t]*9+y[t];
            cnt+=fen[pos]*tnum[t];
        }
        ans=max(ans,cnt);
        return;
    }
    for(Min=N,i=R[0];i;i=R[i])
        if(S[i]<Min) Min=S[i],c=i;
    remove(c);//删除该列
    for(i=D[c];i!=c;i=D[i])
    {
        OK[k]=i;
        for(j=R[i];j!=i;j=R[j])
            remove(C[j]);
        Dance(k+1);
        //if(flag) return;//只要一组解
        for(j=L[i];j!=i;j=L[j])
            resume(C[j]);
    }
    resume(c);
}
/*
试构造一个矩阵,其中以行表示概然,以列表示约束。
行所表示的概然状态为(r,c,k)即在棋盘r行c列放置数字k。
列所表示的约束分做四种,即改当前方案r行中是否放置数k,c列中是否放置数k,
(r,c)格中是否放置数k以及块b(即所属区域)是否放置数k。
因此行总共有N*N*N=9*9*9=729个,列总共有9*9*4=324个,要求取若干数字摆放的方案(行),
使每个数字在棋盘的行、列、区域块中(列)只出现一次(1个‘1’),问题转化为729*324的
矩阵的精确覆盖。特别的,(r,c)格的约束保证了我们最后可行解的一定为N*N。
*/
char str[100];
int mat[N][N];
int a[10][10];
int tof(int x,int y)
{
    return x*9+y;
}
int main()
{
    for(int i=0;i<5;i++)
    {
        for(int j=i;j<9-i;j++)
            fen[tof(i,j)]=i+6,fen[tof(9-i-1,j)]=i+6,
            fen[tof(j,i)]=i+6,fen[tof(j,9-i-1)]=i+6;
    }
    //for(int i=0;i<9;i++){for(int j=0;j<9;j++) printf("%-3d",fen[tof(i,j)]);printf("\n");}
    while(scanf("%d",&a[0][0])==1)
    {
        for(int i=0;i<9;i++) for(int j=0;j<9;j++)
            if(i||j) scanf("%d",&a[i][j]);
        //DLX
        m=9*9*4;//列数
        n=0;//构图花费时间比较多  应该直接构图 不用mat数组  这样会快很多
        for(int i=0;i<=m;i++)
        {
            S[i]=0;
            D[i]=U[i]=i;
            L[i+1]=i;R[i]=i+1;
        }R[m]=0;
        size=m+1;
        memset(H,-1,sizeof(H));
        memset(mark,0,sizeof(mark));//不用mat数组,这样可以加快速度
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
            {
                int row=i;
                int col=j;
                int kuai=(i-1)/3*3+(j-1)/3+1;
                int pos=(i-1)*9+j;
                if(a[i-1][j-1]==0)//可以放数字
                {
                    for(int k=1;k<=9;k++)
                    {
                        ++n;
                        tnum[n]=k;x[n]=i-1,y[n]=j-1;
                        Link(n,(row-1)*9+k);//行
                        Link(n,81+(col-1)*9+k);//列
                        Link(n,162+(kuai-1)*9+k);//块
                        Link(n,243+pos);//位置
                    }
                }
                else//已经放数字
                {
                    int k=a[i-1][j-1];
                    ++n;
                    tnum[n]=k;x[n]=i-1,y[n]=j-1;
                    Link(n,(row-1)*9+k);//行
                    Link(n,81+(col-1)*9+k);//列
                    Link(n,162+(kuai-1)*9+k);//块
                    Link(n,243+pos);//位置
                }
            }
        }
        flag=0,ans=0;
        Dance(0);
        if(flag) printf("%d\n",ans);
        else printf("-1\n");
    }
    return 0;
}
/*
7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2

0 0 0 7 0 2 4 5 3
9 0 0 0 0 8 0 0 0
7 4 0 0 0 5 0 1 0
1 9 5 0 8 0 0 0 0
0 7 0 0 0 0 0 2 5
0 3 0 5 7 9 1 0 8
0 0 0 6 0 1 0 0 0
0 6 0 9 0 0 0 0 1
0 0 0 0 0 0 0 0 6

2829   2852
*/

nankai 2082: 靶形数独 数独(9*9)求所有解 DLX+精确覆盖相关推荐

  1. JS 中的 event?event:window.event什么意思?求详解。

    JS 中的 event?event:window.event什么意思?求详解. 2013-04-16 00:01flying607 | 分类:JavaScript |浏览813次 <script ...

  2. 5.C语言二分法求方程解

    用二分法求方程解 #include <stdio.h> #include <math.h> double f(double x){return x*x-2*x-1; } dou ...

  3. matlab抛物偏微分方程,抛物型方程差分求解 跪求MATLAB解抛物型偏微分方程的程序...

    为什么抛物线方程与圆方程联立不能使用韦达定理 很容易了解到,抛物线和圆的交点均在X轴上方\"其实这时你应该注意到一点就是,这两个交点的纵坐标是相等的,所以其实对应的是一个y值,也就是你列的一 ...

  4. 不求甚解与求甚解的阶段区分

    前几日砍瓜切菜般搭建了一个简单的网站,之后便进入一段目标迷茫期,同时也深知自己立足未稳,基础未牢:往前走又有诸多岔路口,毫无疑问会分散自己本就不多的精力. 我是继续不求甚解地走下去:用同样的手法搞定C ...

  5. 马踏棋盘求----全部解

    标题:运用栈和回溯法求马踏棋盘的全部解 回溯法的写法参考<数据结构–严蔚敏>的迷宫求解 感谢我的队友-汪汪汪 他与求一个解不同之处在于,当我们求到一个解之后,这个程序却会告诉计算机:&qu ...

  6. 九宫格数独c语言编程,求用C语言编一个解九宫格数独的程序

    满意答案 emhw637617 2013.12.30 采纳率:59%    等级:12 已帮助:5603人 前两天刚写完,还没优化,已运行通过了. 晕,一维的好麻烦,这个也是碰巧前两天刚写好的,你看着 ...

  7. 徐松亮算法教学-基于C语言的数独(九宫格)求解(含多解和解数统计)

    版权声明:本文为博主徐松亮的原创作品,未经允许不得转载,多谢支持!QQ:5387603 推荐点击此链接:欢迎进入徐松亮博客一站式导航搜索(随时更新) 目录 一,前言 二,开发环境 电脑系统 编译器 编 ...

  8. LintCode 802. 数独(回溯)/ LeetCode 37. 解数独

    1. 题目 编写一个程序,通过填充空单元来解决数独难题. 空单元由数字0表示. 你可以认为只有一个唯一的解决方案. LeetCode 37 题类似,把 int 改成 char,注意转换 2. 解题 行 ...

  9. 【数独 2】候选数法解数独谜题-挖掘更深的信息-C++实现

  10. C语言二分法求最小值解,C语言用二分法求方程的近似解的方法

    基础知识以下地址: http://jingyan.baidu.com/article/597a06438def54312a524376.html 我的应用如下:求x^5+x^3+7=0,求取x的值是多 ...

最新文章

  1. 算法----Excel 表中相对应的列名称
  2. Go语言学习(七)-----练练笔之递归
  3. java判断时间区间 隔天_Java初中级程序员面试题宝典
  4. 解析OA技术,规避使用风险
  5. 按相反的顺序输出列表的元素python_Python练习实例32 | 如何以相反的顺序来输出列表的值?...
  6. myeclipse jsp和java字体设置
  7. 10岁女程序员,婉拒谷歌Offer,研发全球首款AI桌游,现在是一名CEO
  8. 在Ubuntu下使用Apt-Get安装Google Chrome
  9. pyclewn调试带参数程序
  10. .netcore mvc docker环境jenkins一键部署(DevOps)
  11. dirent struct_关于readdir返回值中struct dirent.d_type的取值有关问题(转)
  12. AnySdk渠道列表
  13. 虚拟化:十大虚拟化最佳实践
  14. windows聚焦壁纸不更新_如何解决Win10聚焦锁屏壁纸不自动更新的问题
  15. 粉象生活日记1:系统化打磨
  16. Codeforces Round #572(div2)部分题解(A~C,E)
  17. 计算机怎么发音乐,网易云音乐怎么分享音乐给别人的教程
  18. 服务器被黑怎么用防御系统解决
  19. 2022年5月月度总结
  20. git向多个分支push

热门文章

  1. 西刺代理python_Python四线程爬取西刺代理
  2. windows虚拟显示器开发(三)USB显示器
  3. 三星sm-g7106com.android.mms,三星g7106官方原版固件rom系统刷机包_三星g7106线刷包
  4. 目前最值得推荐的几款黑科技APP,快来收藏吧!
  5. OpenDDS系列(1) —— OpenDDS 简介
  6. 水经微图与万能地图下载器功能比较
  7. php 连接芒果数据库,芒果数据库配置文件
  8. matlab各种文件类型,MATLAB中的文件类型总结
  9. 微信小程序直播为什么这么受欢迎
  10. Linux网络命令之 `Hping3`