• 中山大学校队选拔赛第一章题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:
    ",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函数时剪枝技巧的利用。

  • 相关阅读:
    js中split字符串分割
    获取日期,实时显示当前时间,时间相减
    5.5.4 函数内部属性
    单选按钮radio和下拉选择select,ajax返回数据回显对应值
    如何在HTML不同的页面中,共用头部与尾部?
    android-Activity(四大组件之一)
    android-ImageView及其子类
    android-ActionBar
    android- 菜单
    android-Fragment
  • 原文地址:https://www.cnblogs.com/khbcsu/p/4255514.html
Copyright © 2020-2023  润新知