caioj1044:简单数密(深搜+数独+求和)

要登录才能看题目:题目传送门

题目大意:

1、在数独的基础上,加入每行每列求和的条件;

上代码:

//caioj1044 简单数迷
//题解:深搜+剪枝 
#include<cstdio>
#include<cstring>
 
int hs[20],ls[20],fx[20][20],fy[20][20];
int a[20][20],b[20][20];
int n,m,ans;
 
void dfs(int x,int y)
{
    if(ans>1) return ;
    if(x>n)//全图搜完了,有答案 
    {
        for(int i=1;i<=m;i++)//必须每列都刚好 
        {
            if(ls[i]!=0) return ;
        }
        ans++;
        if(ans==1)
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                {
                    b[i][j]=a[i][j];
                }
            }
        }
        return ;
    }
    if(y>m&&hs[x]==0) { dfs(x+1,1); return ; }//搜完一行了 
     
    if(a[x][y]!=0) { dfs(x,y+1); return; }//不用填
     
    for(int i=1;i<=9;i++)//需要填 
    {
        if(hs[x]-i>=0&&ls[y]-i>=0&&
           fx[x][i]==0&&fy[y][i]==0)
        {
            hs[x]-=i; ls[y]-=i;
            fx[x][i]=1;fy[y][i]=1;
            a[x][y]=i;
            dfs(x,y+1);
            hs[x]+=i; ls[y]+=i;
            fx[x][i]=0;fy[y][i]=0;
            a[x][y]=0;
        }
    }
      
}
 
int main()
{
    int t; scanf("%d",&t);
    while(t--){
         
    scanf("%d %d",&n,&m);
    ans=0;
    memset(fx,0,sizeof(fx));
    memset(fy,0,sizeof(fy));
    for(int i=1;i<=n;i++) scanf("%d",&hs[i]);
    for(int i=1;i<=m;i++) scanf("%d",&ls[i]);
     
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) 
        {
            scanf("%d",&a[i][j]);
            hs[i]-=a[i][j];
            ls[j]-=a[i][j];
            fx[i][a[i][j]]=1;
            fy[j][a[i][j]]=1;
        }
    }
     
    dfs(1,1);
     
    if(ans==1)
        for(int i=1;i<=n;i++) 
        {
            for(int j=1;j<m;j++)
            {
                printf("%d ",b[i][j]);
            }
            printf("%d\n",b[i][m]);
        }
         
    if(ans==0) printf("No answer.\n");
     
    if(ans>1) printf("Not unique.\n");
     
    }
     
    return 0;
}

猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/82465619