中山大学校队选拔赛第一章题4【简单数迷Simple Kakuro】-------2015年1月28日

一:题意描述

本题就是给定一个迷宫,其中第一行和第一列都给定了数值。现在我们的任务就是需要把剩余的空格用1-9的数字把它填满,并且每行每列数值之和需要和行列标定的值相等。问最后是否可行,如果有多种方案需要输出一种方案。

二 :题目分析

本题主要考查DFS当中剪枝技巧的利用以及DFS的方向规划问题。

首先我们可以根据题目已知信息得出行之和必须等于列之和。(第一次剪枝)

然后我们可以根据每一个数字不能在同一行或者同一列重复出现【设定标记】进行剪枝(第二次剪枝)

对于如果某一行(一列)数值还没有填满但是总和已经超过行列标定值之和,或者填满了但是总和和标定值不相等,那么我们必须剪枝。(第三次剪枝)

对于规划方向,我们可以采取从左到右从上到下的方式进行,当我们深搜把最后一个点深搜完毕时我们即可结束DFS,当然当sol(解决办法)>1时也可以结束递归。

三:AC代码

#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define maxn 300+10
#define MOD 1000000000
int sumrow[11],sumcol[11];//行列指定值之和
int a[11][11],mark[11][11];//标记矩阵确定是否已经填上了数字
int  n,m;
int curSumrow[11],curSumcol[11];//已经填上的行列值和
int sol;
int ans[11][11];
int usedrow[11][10],usedcol[11][10];
void Search(int x,int y)
{
    if(sol>1)  return;//说明有多种输出方案
    if(x==n)//表明已经合乎要求
    {
        sol++;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            ans[i][j]=a[i][j];
        return;
    }
    int nx,ny;
    if(y==m-1)
    {
        nx=x+1;
        ny=0;
    }
    else
    {
        nx=x;
        ny=y+1;
    }
    if(mark[x][y])
    {
        int ok=1;
        if(y<m-1&&curSumrow[x]>sumrow[x]||y==m-1&&curSumrow[x]!=sumrow[x])
        ok=0;
        if(x<n-1&&curSumcol[y]>sumcol[y]||x==n-1&&curSumcol[y]!=sumcol[y])
        ok=0;
        if(ok) Search(nx,ny);
        return;
    }
    for(int i=1;i<10;i++)
    if(!usedrow[x][i]&&!usedcol[y][i])
    {

        usedcol[y][i]=1;
        usedrow[x][i]=1;
        curSumcol[y]+=i;
        curSumrow[x]+=i;
        a[x][y]=i;
        int go=1;
        if(y<m-1&&curSumrow[x]>sumrow[x]||y==m-1&&curSumrow[x]!=sumrow[x])
          go=0;
        if(x<n-1&&curSumcol[y]>sumcol[y]||x==n-1&&curSumcol[y]!=sumcol[y])
          go=0;
        if(go) Search(nx,ny);
        a[x][y]=0;
        usedcol[y][i]=0;
        usedrow[x][i]=0;
        curSumcol[y]-=i;
        curSumrow[x]-=i;
    }
}
int main()
{
    int T;
    int cas;

    int sumR,sumC;
    cin>>T;
    for(cas=1;cas<=T;cas++)
    {
        cin>>n>>m;
        sumC=sumR=0;
        int ok=1;
        memset(mark,0,sizeof(mark));
        memset(usedcol,0,sizeof(usedcol));
        memset(usedrow,0,sizeof(usedrow));
        memset(curSumcol,0,sizeof(curSumcol));
        memset(curSumrow,0,sizeof(curSumcol));
        for(int i=0;i<n;i++) {cin>>sumrow[i];sumR+=sumrow[i];}
        for(int j=0;j<m;j++) {cin>>sumcol[j];sumC+=sumcol[j];}
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            cin>>a[i][j];
            if(a[i][j]>0)
            {
                mark[i][j]=1;
                sumcol[j]+=a[i][j];
                sumrow[i]+=a[i][j];
                usedrow[i][a[i][j]]++;
                usedcol[j][a[i][j]]++;
                if(usedrow[i][a[i][j]]>1) ok=0;
                if(usedcol[j][a[i][j]]>1) ok=0;
            }
        }
//        for(int i=0;i<n;i++)
//        if(curSumrow[i]>sumrow[i]) ok=0;
//        for(int j=0;j<m;j++)
//            if(curSumcol[j]>sumcol[j]) ok=0;
        if(sumC!=sumR) ok=0;
         sol=0;
         cout<<ok<<endl;
        if(ok)
            Search(0,0);
        printf("Case %d:\n",cas);
        if(sol==0) cout<<"No answer."<<endl;
        else if(sol>1) cout<<"Not unique."<<endl;
        else{
            for(int i=0;i<n;i++)
            {
                 for(int j=0;j<m-1;j++)
                cout<<ans[i][j]<<‘ ‘;
                cout<<ans[i][m-1]<<endl;
            }
        }
    }
    return 0;
}

四:总结

本题主要考察DFS的变式应用,以及对于设计DFS函数时剪枝技巧的利用。

时间: 2024-10-05 19:09:45

中山大学校队选拔赛第一章题4【简单数迷Simple Kakuro】-------2015年1月28日的相关文章

中山大学校队选拔赛第一章题1【紧急逃离Emergent escape】----2015年1月26日

一: 题意描述 二:题目分析 本题的大致意思是讲:在给定的一个大圆上挖去很多圆(这些圆有的在大圆里面,有的在大圆外面,有的与圆相加),凡是被圆占据的部分则不能通行. 现在给定两个点,(lifeship和controlling room)如果两者能够到达的话表示能够Escape,否则就只有Die hard. 本题的主要考查图论知识和计算几何方面的知识.首先我们对于这个问题需要建模.我们首先可以把这个大圆看成单独的一个区域.现在的问题就是在整个大圆内找不到一条线可以让lifeship和control

中山大学校队选拔赛第一章题1【计算生成树】------2015年1月23日

1.1问题描述 1.2问题分析 本题主要考查图论中生成树及组合数学的求法.通过观察我们可以发现当输入为n时,我们一共有(5*n-n)=4n个点.通过思考我们可以知道,要想求得生成树,我们必须使所有五角形的圈全部破掉.那么我们可以思考: 如果对于一个五角形而言,它的每一条边都不删除,那么我们可以发现这必定不能构成生成树,因为这会导致在五角形内任意两个点会至少含有两条路径,不符合生成树的含义.所以我们可以得出如下结论: (1)对于有边数为n的回圈,我们可以发现一共有4n个点,共有5n条边.根据生成树

中山大学校队选拔赛第二试题试题3【Compressed suffix array】-------2015年2月8日

一:题目大意 本题通过给定三个数组S0,P,S,其中S0是1到2n的一个排列,P具有2n个整数,且满足: 数组S是把数组S0中所有奇数元素全部删除并将所有偶数元素除以2并按照原来的相对顺序进行排列而得. 现在给定数组S和数组P,我们需要反求数组S0. 二:题目分析 我们通过对数组P的递推式分析可知:当数组S0的元素是偶数时,这个元素所对应的Pi的值一定等于i.当数组S0的元素为奇数时,我们可以知道对应的Pi一定不等于i.那么我们可以先对数组P扫一遍,把存在Pi=i的元素全部填好,然后再对数组P重

中山大学选拔赛第一章题1【计算生成树】------2015年1月23日

1.1问题描述 1.2问题分析 本题主要考查图论中生成树及组合数学的求法.通过观察我们可以发现当输入为n时,我们一共有(5*n-n)=4n个点.通过思考我们可以知道,要想求得生成树,我们必须使所有五角形的圈全部破掉.那么我们可以思考: 如果对于一个五角形而言,它的每一条边都不删除,那么我们可以发现这必定不能构成生成树,因为这会导致在五角形内任意两个点会至少含有两条路径,不符合生成树的含义.所以我们可以得出如下结论: (1)对于有边数为n的回圈,我们可以发现一共有4n个点,共有5n条边.根据生成树

第一金早评 - 2015年01月07日-晨早快訊

每日金市速遞 (2015年01月07日) 谢权东 先生 上日9999 金粒賣出價每両 HKD 12590 金粒賣出價資料參考周生生,周大福 即日投資策略: 黃金日線圖上分析,日線收3連陽,K線沿布林帶中軌和上軌之間運行,金價日內大漲,布林帶有向上開口跡象,布林中軌向上翹頭,短週期均線指標金叉向上,MACD快慢線死叉於0軸下方金叉,有上穿0軸趨勢,紅柱放量. 從4小時來看,布林帶向上開口,金價處於布林上軌1220與MA5-1215之間震盪往上,短週期均線指標金叉向上,MACD快慢線於0軸附近形成金

我的Python成长之路---第一天---Python基础(1)---2015年12月26日(雾霾)

2015年12月26日是个特别的日子,我的Python成之路迈出第一步.见到了心目中的Python大神(Alex),也认识到了新的志向相投的伙伴,非常开心. 尽管之前看过一些Python的视频.书,算是有一点基础.但在这里我要保持空杯心态,一切从头开始.好了不多说,Let's Python!!!! 一.Python简介 Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言.目前Python已经成为实际上除了中国最流行的开发语

Oyk的ACM刷题记录(始于2015年2月29日,可能含剧透)

Online Judge 题目序号/题目 简单大意/题解 犯2情况 2月29日 SPOJ GSS1  不带更新区间最大子段和. 线段树维护 区间从左/右开始的最大值.区间最大值.区间和. 1.输出忘了换行. 2.打错了一个字母. SPOJ GSS2 区间不重复最大子段和. 离线维护s[i..now],线段树维护 区间历史最大值.区间历史最大更新值.区间现在最大值.区间现在更新值. 询问输出区间历史最大值. 1.线段树询问忘记写pushdown了. SPOJ TEST 输出所有42前的数. 1.不

第三章 管道符、重定向与环境变量 2019年7月17日星期三 第四课

2019年7月17日星期三   第四课 2.7 文件目录管理命令 1.touch命令    创建空白文件或设置文件时间 如:touch haha.txt touch -d “19:00”   修改文件访问和者修改时间 -a 修改读取时间   -m 修改修改时间 -d前两个都修改 2.mkdir命令    创建目录 如果要创建迭代关系的目录要加参数  -p 如:mkdir -p a/b/c/d/e/f/g 3.cp命令    复制文件或目录 复制目录时要加参数 -r 如:cp -r Music/

中山大学校队内部选拔赛试题3.1【Factorial Factors】--------2015年2月9日

一:题目大意 当给定一个数时,先求出它的所有因子N1,N2······Nk,然后求出它的因子对应的因子的个数n1,n2·····nk,并求出最终结果S=n1^3+n2^3+n3^3+·····+nk^3. 二:题目分析 本题的数据范围是N<2^31.如果对于每一趟直接判断时间复杂度将会很高.因此我们需要做预处理,先求出在最大范围内所有的质数. 对于每一个质数p,它的因子只有1和p本身,那么S(p)=1+2^3=9. 对于数字x=p^k,我们可以得知它有1,p,,,,p^k这么多因子,那么S(x)