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