Gym - 100935G G. Board Game

Problem G. Board Game

Input: standard input

Output: standard output

Balloon Color: Orange

Feras bought to his nephew Saleem a new game to help him learning calculating. The game consists ofa board with 4 rows and 4 columns with 16 cubes. Every cube has a number from 1 to 16. Let’s definethe power of a column as the sum of its elements. In the same way, the power of a row is the sum of itselements. Saleem should arrange the cubes in the board such that the power of all columns and all rowsare equal. To make the game easier, the nice uncle, Feras, will help him arranging 7 cubes, and Saleemshould arrange the rest of the cubes.

Input

Your program will be tested on one or more test cases. The first line of the input will be a single integerT, the number of test cases (1 ≤ T ≤ 100). Then the test cases. Each test case has four lines containingfour integers. The j-th number in the i-th line describes the cell (i,j) of the board. If the number is -1 thenthe cell is empty and you have to fill it, otherwise, uncle Feras has already filled this cell.

Output

For each test case print a line in the following format: "Case c:"where c is the test case number startingfrom 1 then print the board in four lines every line has four numbers separated by space. If there is morethan one solution print the solution that has the smallest order (See the notes below).

Examples

standard input 

1

-1 -1 -1 -1

-1 -1 -1 -1

-1 5 13 12

3 8 9 14

standard output

Case 1:

11 6 10 7

16 15 2 1

4 5 13 12

3 8 9 14

Note

in the sample input there is more than one solution:

Solution1:

16 15 2 1

11 6 10 7

4 5 13 12

3 8 9 14

Solution2:

11 6 10 7

16 15 2 1

4 5 13 12

3 8 9 14

but we select solution2 because it has the smallest order when we write the rows in one line.

Solution1: 16 15 2 1 11 6 10 7 4 5 13 12 3 8 9 14

Solution2: 11 6 10 7 16 15 2 1 4 5 13 12 3 8 9 14

题意:

把1到16这些数放入一个4*4的矩形,使得每一行和每一列数加和都相等,已经放好7个数字,剩下9个数没放,求满足条件的矩形字典序最小的方案。

思路:

直接对每一个需要放的位置进行dfs,之后对其进行剪枝。

剪枝技巧:当某行或某列已填满数字,记录下其和,我们就可以在后面dfs时利用这个和进行填数的合法性进行校对,可省去不少时间。

代码有点乱且冗余。。。不过剪枝剪为15ms还是让我有点飘了O(∩_∩)O。

示例程序:

#include <bits/stdc++.h>
using namespace std;
int b[9],vis[9],flag,a[4][4],r[4],c[4],rmark[4],cmark[4];
void dfs(int deep,int buff,int num)
{
    int i,i1;
    if(flag==1)				//找到正解就不用找了
    {
        return;
    }
    if(deep==16)
    {
        for(i=0;4>i;i++)
        {
            for(i1=0;4>i1;i1++)
            {
                if(i1!=0)
                {
                    printf(" ");
                }
                printf("%d",a[i][i1]);
            }
            printf("\n");
        }
        flag=1;
        return;
    }
    if(a[deep/4][deep%4]!=-1)					//该位已填数直接到下一个
    {
        dfs(deep+1,buff,num);
        return;
    }
    for(i=0;9>i;i++)
    {
        if(vis[i]==0)
        {
            vis[i]=1;
            r[deep/4]=r[deep/4]+b[i];
            c[deep%4]=c[deep%4]+b[i];
            rmark[deep/4]=rmark[deep/4]+(1<<(deep%4));
            cmark[deep%4]=cmark[deep%4]+(1<<(deep/4));
            a[deep/4][deep%4]=b[i];				//以上进行填数后的状态更新
            if(cmark[deep%4]==15||rmark[deep/4]==15)			//填数后已把该行或列填满
            {
                if(buff==0)			//这是第一次填满,下面就利用和(num)去进行边填边校对
                {
                    if(rmark[deep/4]==15)				//行填满的情况
                    {
                        dfs(deep+1,1,r[deep/4]);
                    }
                    else if(cmark[deep%4]==15)			//列填满的情况
                    {
                        dfs(deep+1,1,c[deep%4]);
                    }
                }
                else				//不是第一次填满,就看看和(num)是否等于填满行或列的和
                {
                    if((r[deep/4]==num||rmark[deep/4]!=15)&&(c[deep%4]==num||cmark[deep%4]!=15))
                    {
                        dfs(deep+1,buff,num);
                    }
                }
            }
            else				//没有填满任何行列,继续dfs
            {
                dfs(deep+1,buff,num);
            }
            a[deep/4][deep%4]=-1;			//以下是回溯
            vis[i]=0;
            r[deep/4]=r[deep/4]-b[i];
            c[deep%4]=c[deep%4]-b[i];
            rmark[deep/4]=rmark[deep/4]-(1<<(deep%4));
            cmark[deep%4]=cmark[deep%4]-(1<<(deep/4));
        }
    }
}
int main()
{
    int t,i,i1,i2,buff,num,mark[17],top;
    scanf("%d",&t);
    for(i=1;t>=i;i++)
    {
        memset(r,0,sizeof(r));				//r数组记录每行数的和
        memset(c,0,sizeof(c));				//c数组记录每列数的和
        memset(mark,0,sizeof(mark));			//mark数组记录1到16有没有出现过
        memset(rmark,0,sizeof(rmark));			//rmark数组用二进制表示每行填数的情况
        memset(cmark,0,sizeof(cmark));			//cmark数组用二进制表示每列填数的情况
        buff=0;				//buff表示是否有一行或一列已填满数,dfs函数中的buff同理
        for(i1=0;4>i1;i1++)
        {
            for(i2=0;4>i2;i2++)
            {
                scanf("%d",&a[i1][i2]);
                if(a[i1][i2]!=-1)
                {
                    mark[a[i1][i2]]=1;
                    r[i1]=r[i1]+a[i1][i2];
                    c[i2]=c[i2]+a[i1][i2];
                    rmark[i1]=rmark[i1]+(1<<i2);
                    cmark[i2]=cmark[i2]+(1<<i1);
                    if(rmark[i1]==15)				//当rmark为15,那么有一行已填满数
                    {
                        buff=1;
                        num=r[i1];
                    }
                    else if(cmark[i2]==15)				//当cmark值为15,那么有一列已填满数
                    {
                        buff=1;
                        num=c[i2];
                    }
                }
            }
        }
        top=0;
        for(i1=1;16>=i1;i1++)
        {
            if(mark[i1]==0)
            {
                b[top++]=i1;				//取出需要填放的数
            }
        }
        flag=0;
        memset(vis,0,sizeof(vis));
        printf("Case %d:\n",i);
        dfs(0,buff,num);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值