zju1008题解Gnome Tetravex

Gnome Tetravex

Time Limit: 10 Seconds       Memory Limit: 32768 KB

Hart is engaged in playing an interesting game, Gnome Tetravex, these days. In the game, at the beginning, the player is given n*n squares. Each square is divided into four triangles marked four numbers (range from 0 to 9). In a square, the triangles are the left triangle, the top triangle, the right triangle and the bottom triangle. For example, Fig. 1 shows the initial state of 2*2 squares.


Fig. 1 The initial state with 2*2 squares

The player is required to move the squares to the termination state. In the termination state, any two adjoining squares should make the adjacent triangle marked with the same number. Fig. 2 shows one of the termination states of the above example.


Fig. 2 One termination state of the above example

It seems the game is not so hard. But indeed, Hart is not accomplished in the game. He can finish the easiest game successfully. When facing with a more complex game, he can find no way out.

One day, when Hart was playing a very complex game, he cried out, "The computer is making a goose of me. It's impossible to solve it." To such a poor player, the best way to help him is to tell him whether the game could be solved. If he is told the game is unsolvable, he needn't waste so much time on it.


Input

The input file consists of several game cases. The first line of each game case contains one integer n, 0 <= n <= 5, indicating the size of the game.

The following n*n lines describe the marking number of these triangles. Each line consists of four integers, which in order represent the top triangle, the right triangle, the bottom triangle and the left triangle of one square.

After the last game case, the integer 0 indicates the termination of the input data set.


Output

You should make the decision whether the game case could be solved. For each game case, print the game number, a colon, and a white space, then display your judgment. If the game is solvable, print the string "Possible". Otherwise, please print "Impossible" to indicate that there's no way to solve the problem.

Print a blank line between each game case.

Note: Any unwanted blank lines or white spaces are unacceptable.


Sample Input

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


Output for the Sample Input

Game 1: Possible

Game 2: Impossible


题目大意:

在N*N的方格中,每一个方格有四个三角形按照上右下左的顺序次序排列,然后移动方格,是那些相邻的方格,满足相邻的对应三角形的值相等,有时候是无解的,有时候有解,题目就是让写下程序来判断给定一个方格看看是否能满足题意,如果能就打印possibble

如果不能就打印impossible


分析题意:

显然没有其他别的思路的情况下,只能用搜索了,其实也就是枚举或者说是全排列,只不过是这里对象不是数字的按照一定的顺序排列而是图形按照一定的规则来进行排列,

我们把所有的情况都给看看,如果能拼成,那就可以,如果所有的情况都找不到,那就是不可能了。

    所以下面其实就是来想想用全排列,把每一个方格所出现的可能性都给试一遍,总会找到结果的。

     那么核心的算法思想就是全排列了,下面简单写下全排列的过程。

如果有N*N个方格的话,按照行的顺序把每一个方格编上序号,从0到n*N-1;


place函数就是在当前位置放块。

//开始的时候初始化所有的tag[i]为false

     int place(int pos){

if(pos==N*N)return 1;//递归的终止条件如果都能放下,那么就一次向上返回一个值1,那么最开始的值也为1.否则下面的那个循环结束后,每一个都试了一遍还找不到返回值1去结束循环的话,那么循环最终结束后就执行return 0说明没有解

for(i=0;i<n*n;i++){

if(!tag[i]&&placeble(i)){

tag[i]=true;

table[pos]=i;

if(place(pos+1)==1)return 1;

tag[i]=false;//每次递归返回后执行当前的循环的时候,都要保持原tag中的值不能改变。这相当于执行该点开始的另一次搜索,所以值不能改变,改变之后一定要换回来。

}

return 0;

}

placeable(i)是判断是否可以在当前位置放置第i个方块的判断函数

上面的方法是一般的方法,但是带来很大的为题就是当n为5时,那就是25的阶乘,数会非常的大,很耗时,所以要进行优化。

通过分析,我们发现,这些块中如果存在很多重复的块(块的种类相同)时,这样做就太浪费了,所以我们可以不用按照块的数目来计算,可以变成块的种类来计算,这样就会大大减小数据量,如果存在10个块相同时,那么就是15的阶乘,会大大减小判断的情况,其实说到底就是说,这个全排列中可能会存在那些相同的项,死板的用数目 阶乘是不合理的,我们要判断是否有相同项,如果有的话,我们要进行处理,问题则转化为,求可能含有相同项的阶乘问题。


这样的话,我们就可以首先来统计下,这些块有那些种类,然后按照种类的个数来进行判断,这样就减少了工作量。

下面就是源码以及注释

#include<stdio.h>
//数据结构
int square[25][4];//最多有25个块,每个块里有四个部分,分别用一行的数组来表示可以体现他们的顺序关系 
int q;//总的块的种类个数 
int kindcount[25];//总的种类可能有25种,这是最坏的情况,如果有相同的类型的话,那么就把对应那个值加1
//也就是说,这个数组里面保存的是每种种类的个数, 注意该数组可能用不完那么多,只用了q个,每一个
//都保存着这种种类编号的个数 


int n;
int table[25];//当前实际位置放置的种类
int place(int pos){
    if(pos==n*n)return 1;
    for(int i=0;i<q;i++){//对于每次的一个循环其实就是一次搜索,注意跟深度搜索联系,这里跟最后那个为什么要恢复也有联系,两者联系起来理解更好 
        if(kindcount[i]==0)continue;//如果该种种类的数目为零则找下一个 
        if(pos%n!=0)//如果不是最左边就水平判断 
            if(square[table[pos-1]][1]!=square[i][3])continue;
            //如果不是第一行就垂直判断 
        if(pos>=n)if(square[table[pos-n]][2]!=square[i][0])continue;
        table[pos]=i;
        kindcount[i]--;
        if(place(pos+1)==1)return 1;
        kindcount[i]++;//此处一定要恢复过来,因为这个数组就相当于一个固定保存器,它里面的值一次搜索完成后都要回复原来的样子
        //不然这个数组的值都改变了,我们该怎么判断呢?这点不容易理解,要多想想为什么。 
       }
       return 0;
    }
int main(){
    int iCase=0; 
    while(scanf("%d",&n)&&n){
        int i,j,top,right,bottom,left;
         q=0;
        iCase++;
        for(i=0;i<n*n;i++){
            scanf("%d%d%d%d",&top,&right,&bottom,&left);
            for( j=0;j<q;j++){//每次读进来四个值,就判断是否有重复,如果有就记录下 
                if(square[j][0]==top&&square[j][1]==right&&square[j][2]
                                ==bottom&&square[j][3]==left){
                                    kindcount[j]++;
                                    break;
                                    //如果有重复那么当前这个值就不必再放到块中了,因为我们是为了初始化kindcount的值 
                                    }
                }
                if(j==q){//如果没有就把值放到当前的块中 
                    square[j][0]=top;
                    square[j][1]=right;
                    square[j][2]=bottom;
                    square[j][3]=left;
                    kindcount[j]=1;
                    q++;
                    }
            }
            if(iCase>1)printf("\n");
            if(place(0)==1)printf("Game %d: Possible\n",iCase);
            else printf("Game %d: Impossible\n",iCase);
        }
        return 0;
    } 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值