XDOJ10033--实验室的新机子

Description

  实验室到了一批新机子,这下可把WM和ZYF高兴坏了,看着配置颇高的新机子,他们决定进行一番压力测试,于是他们打开了经典的游戏——扫雷。-_-!
  扫雷的规则很简单,雷区是一个16*30的阵列,每个单元要么是一个雷,要么是一个数字,数字表示的是以这个单元为中心的9个单元中雷的个数(如果数字单元贴边则不计落在阵列外的单元)。一旦点到雷则游戏结束,否则可以继续点下去,直到将所有数字点出来。
  ZYF二话不说立马开始乱点,世界上总有某些人运气好到令人发指,ZYF连点了五下竟点出的全是数字,WM认识到这是种缺心眼的行为,并预感到下一次很可能就会点到雷,立马阻止了他。那么根据点出来的数字到底能确定多少个必定是雷的单元呢?
  此处说明一下,我们称两个有相同行坐标而坐标列只差1,或者有相同列坐标而行坐标只差1的单元为相邻的单元。相邻的单元是可达的,而拥有共同的可达单元的两个单元之间也是可达的。ZYF点开的几个单元之间就是相互可达的。

Input

输入数据的第一行是一个正整数T(1≤T≤100),表有T组待测数据,每组待测数据的第一行为一正整数N(1≤N≤5),为ZYF已点开的单元数,接下来N行, 每行三个正整数X、Y和S(1≤X≤16, 1≤Y≤30, 0≤S≤8)表示点开数字所在单元的坐标和那个数字。

Output

针对每组待测数据,输出一个正整数,表示在阵列上可以确定是雷的单元的个数。由于可能是不稳定的Windows程序错误,所以可能出现数字间矛盾的情况,此时输出0即可。

Sample Input

3
3
3 3 3
4 3 6
4 4 3
1
1 1 3
2
4 4 7
4 5 3

Sample Output

6
3
0

 

解题思路:

这一道题看上去好像不知如何下手,其实如果注意到N个单元最多也就是相邻16个其它单元时,我们就可以用枚举的方式来解答这道题。

算法:

(1)找到与点开单元相邻的所有其它单元

(2)枚举这些单元的组合情况,判断它们是否满足雷数的约束

(3)如果没有任何一种组合满足这种约束,才输入0

(4)如果有多种组合满足这种约束,计算它们共同的部分

#include<iostream>
#include<cmath>
using namespace std;

struct CELL
{
    int x,y,s;
    int cs;
};
CELL cells[5];
struct NEIGHBOR
{
    int x,y;
    bool state;
};
NEIGHBOR neighbors[16];
bool isCandidates [17][31];//mean if this cell has not been open
bool isNeighbor[17][31];//mean if this cell is the neighbor cell of these open cell
int legalCase[65536];
bool isLegal(int posX,int posY)
{
    return ((posX>0&&posX<17)&&(posY>0&&posY<31));
}
bool isToNeighbor(int posX1,int posY1,int posX2,int posY2)
{
    return ((abs(float(posX1-posX2))<2)&&(abs(float(posY1-posY2))<2));
}
int main()
{
    int T;
    cin>>T;//1<=T<=100

        int N;
        for(int i=0;i<T;++i)
        {
            cin>>N;
            for(int j=1;j<17;++j)
            {
                for(int k=1;k<31;++k)
                {
                    isCandidates[j][k] = true;
                    isNeighbor[j][k] = false;
                }
            }
            for(int j=0;j<N;++j)
            {
                int X,Y,S;
                cin>>X>>Y>>S;
                cells[j].x = X;cells[j].y = Y;cells[j].s = S;
                isCandidates[X][Y] = false;
                for(int k=-1;k<2;++k)
                {
                    for(int p=-1;p<2;++p)
                    {
                        if(isLegal(X+k,Y+p))
                            isNeighbor[X+k][Y+p] = true;
                    }
                }

            }
            //求得所有相邻点
            int realNeighbor = 0;
            for(int j=1;j<=16;++j)
            {
                for(int k=1;k<=30;++k)
                {
                    if(isCandidates[j][k]&&isNeighbor[j][k])
                    {
                        neighbors[realNeighbor].x = j;
                        neighbors[realNeighbor].y = k;
                        //cout<<"("<<j<<","<<k<<")"<<endl;
                        neighbors[realNeighbor].state = 0;
                        ++realNeighbor;
                    }
                }
            }
            //枚举所有组合
            int MaxState = 2;
            for(int j=1;j<realNeighbor;++j)
                MaxState *= 2;
            int legalCom = 0;

            for(int j=0;j<MaxState;++j)
            {
                int state = j;
                for(int k=0;k<realNeighbor;++k)
                {
                    if(state&1)
                    {
                        neighbors[k].state = true;
                    }
                    else
                    {
                        neighbors[k].state = false;
                    }
                    state >>= 1;
                }
                for(int p=0;p<N;++p)
                    cells[p].cs = 0;
                //检验一个组合是不是合法的
                for(int k=0;k<realNeighbor;++k)
                {
                    if(neighbors[k].state==true)
                    {
                        for(int p=0;p<N;++p)
                        {
                            if(isToNeighbor(neighbors[k].x,neighbors[k].y,cells[p].x,cells[p].y))
                            {
                                ++cells[p].cs;
                            }
                        }
                    }
                }
                int q;
                for(q=0;q<N;++q)
                {
                    if(cells[q].cs==cells[q].s)
                        continue;
                    else
                        break;
                }

                if(q==N)
                {
                    ++legalCom;
                    legalCase[legalCom] = j;
                }
            }
            if(legalCom==0)
                cout<<0<<endl;
            else
            {
                int temp = legalCase[1];
                for(int k=1;k<=legalCom;++k)
                    temp &= legalCase[k];
                int temp2 = 0;
                while(temp!=0)
                {
                    if(temp&1)
                        temp2++;
                    temp >>=1;
                }
                cout<<temp2<<endl;
            }

        }

    return 0;
}

 

最后欢迎大家访问我的个人网站: 1024s

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值