关于给数扫雷的算法

pavelalex 2007-10-29 02:08:24
加精
已知把雷区的雷布好了,每个格子数字都填好(可见),怎么通过这些数字把雷找出来
一起研究一下算法。
...全文
1485 33 打赏 收藏 举报
写回复
33 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Daniel2081 2009-03-11
学习!!!
  • 打赏
  • 举报
回复
wjlsmail 2007-11-21
Mark, interest......
  • 打赏
  • 举报
回复
mathe 2007-11-15
构造了一个有3个解的局面:
4 4
1 2 2 1
2 3 3 2
2 3 3 2
1 2 2 1

Solution 1:
0000
0110
0110
0000
Solution 2:
1001
1001
1001
1001
Solution 3:
1111
0000
0000
1111
  • 打赏
  • 举报
回复
pavelalex 2007-11-14
math,真的太感谢了
  • 打赏
  • 举报
回复
mathe 2007-11-12
测试发现代码有两个BUG:
i)AllSolutions()

for(s=0;s<N;s++)for(t=0;t<N;t++){ => for(s=0;s<N;s++)for(t=0;t<M;t++){

ii)DumpAllSolutions()

b[2]=x[0][2]; => b[2]=x[1][0];



另外确定了给一个局面的确可能存在多解:
比如3*3
2 3 2
2 5 2
1 3 1
有俩个解:
011
101
100

110
101
001
  • 打赏
  • 举报
回复
mathe 2007-11-12
例子:
输入:
2 4
2 1 2 0
1 2 2 1
(第一行代表输入是两行4列)
输出:
Solution 1:
0101
1000
  • 打赏
  • 举报
回复
mathe 2007-11-12

void AllSolutions(MATRIX x,MATRIX kmatrix, const VECTOR b, int zc,int* index_x, int* index_y)
{
int i;
int sc=0;
VECTOR r=vector_alloc(zc);
MATRIX h=matrix_alloc(N,M);
for(i=0;i<(1<<zc);i++){
int j;
for(j=0;j<zc;j++){
if(i&(1<<j)){
r[j]=1-b[j];
}else{
r[j]=-b[j];
}
}
GaussSolve(kmatrix, r,zc);
matrix_copy(h,x,N,M);
for(j=0;j<zc;j++){
int s,t;
for(s=0;s<N;s++)for(t=0;t<N;t++){
h[s][t]+=r[j]*TN[index_x[j]][s]*TM[t][index_y[j]];
}
}
if(IsValidSolution(h)){
printf("Solution %d:\n",++sc);
SolutionOutput(h);
}
}
if(sc==0){
printf("No solution found\n");
}
matrix_free(h);
vector_free(r);
}

void DumpAllSolutions(MATRIX x)
{
int zero_count=0;
if((M&1)&&(N&1))zero_count++;
if((M+1)%5==0&&(N+1)%5==0)zero_count+=2;
if(zero_count==0){
if(IsValidSolution(x)){
printf("Solution 1:\n");
SolutionOutput(x);
}else{
printf("No valid solution\n");
}
}else{
MATRIX kmatrix=matrix_alloc(zero_count, zero_count);
VECTOR b = vector_alloc(zero_count);
int *index_x = (int *)malloc(sizeof(int)*zero_count);
int *index_y = (int *)malloc(sizeof(int)*zero_count);
switch(zero_count){
case 1://Using value in element (0,0)
index_x[0]=(N+1)/2-1;
index_y[0]=(M+1)/2-1;
kmatrix[0][0]=TN[index_x[0]][0]*TM[0][index_y[0]];
b[0]=x[0][0];
break;
case 2://Using value in element (0,0), (0,1)
index_x[0]=(N+1)/5-1;
index_y[0]=3*(M+1)/5-1;
index_x[1]=3*(N+1)/5-1;
index_y[1]=(M+1)/5-1;
kmatrix[0][0]=TN[index_x[0]][0]*TM[0][index_y[0]];
kmatrix[0][1]=TN[index_x[0]][0]*TM[1][index_y[0]];
kmatrix[1][0]=TN[index_x[1]][0]*TM[0][index_y[1]];
kmatrix[1][1]=TN[index_x[1]][0]*TM[1][index_y[1]];
b[0]=x[0][0];
b[1]=x[0][1];
break;
case 3://Using value in element (0,0),(0,1),(1,0)
index_x[0]=(N+1)/2-1;
index_y[0]=(M+1)/2-1;
index_x[1]=(N+1)/5-1;
index_y[1]=3*(M+1)/5-1;
index_x[2]=3*(N+1)/5-1;
index_y[2]=(M+1)/5-1;
kmatrix[0][0]=TN[index_x[0]][0]*TM[0][index_y[0]];
kmatrix[0][1]=TN[index_x[0]][0]*TM[1][index_y[0]];
kmatrix[0][2]=TN[index_x[0]][1]*TM[0][index_y[0]];
kmatrix[1][0]=TN[index_x[1]][0]*TM[0][index_y[1]];
kmatrix[1][1]=TN[index_x[1]][0]*TM[1][index_y[1]];
kmatrix[1][2]=TN[index_x[1]][1]*TM[0][index_y[1]];
kmatrix[2][0]=TN[index_x[2]][0]*TM[0][index_y[2]];
kmatrix[2][1]=TN[index_x[2]][0]*TM[1][index_y[2]];
kmatrix[2][2]=TN[index_x[2]][1]*TM[0][index_y[2]];
b[0]=x[0][0];
b[1]=x[0][1];
b[2]=x[0][2];
break;
}
AllSolutions(x,kmatrix,b,zero_count,index_x,index_y);
free(index_x);
free(index_y);
vector_free(b);
matrix_free(kmatrix);
}
}

int main(){
int i,j;
MATRIX x;
MATRIX r;
if(scanf("%d %d",&N,&M)!=2){
fprintf(stderr,"Invalid input\n");
return -1;
}
if(N<=0||M<=0){
fprintf(stderr,"Invalid input\n");
return -1;
}
init();
x=matrix_alloc(N,M);
r=matrix_alloc(N,M);
for(i=0;i<N;i++)for(j=0;j<M;j++){
int d;
if(scanf("%d",&d)!=1){
fprintf(stderr,"Invalid data\n");
return -2;
}
r[i][j]=(ftype)d;
}
if(Solve(x,r)){
DumpAllSolutions(x);
}else{
printf("No valid solution\n");
}
matrix_free(r);
matrix_free(x);
fini();
return 0;
}

  • 打赏
  • 举报
回复
mathe 2007-11-12

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
typedef double ftype;
typedef ftype ** MATRIX;
typedef ftype * VECTOR;
typedef const ftype *const*const CONST_MATRIX;
typedef const ftype * CONST_VECTOR;
#define INIT_a 0.0
#define INIT_b 100.0
#define INIT_c 75.0
#define INIT_d 50.0
#define ERROR 0.000001
MATRIX matrix_alloc(int n, int m){
MATRIX x = (MATRIX)malloc(sizeof(ftype *)*n+sizeof(ftype)*n*m);
int i;
x[0]=(ftype *)(x+n);
for(i=1;i<n;i++)x[i]=x[i-1]+m;
return x;
}

void matrix_free(MATRIX x){
free(x);
}

VECTOR vector_alloc(int n){
VECTOR x = (VECTOR)malloc(sizeof(ftype)*n);
return x;
}

void vector_free(VECTOR x){
free(x);
}

//A+=B; n rows m columns
void matrix_sum(MATRIX A, CONST_MATRIX B, int n, int m){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
A[i][j] += B[i][j];
}
}
}

//A-=B; n rows m columns
void matrix_diff(MATRIX A, CONST_MATRIX B, int n, int m){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
A[i][j] -= B[i][j];
}
}
}
//a+=b;
void vector_sum(VECTOR a, CONST_VECTOR b, int n){
int i;
for(i=0;i<n;i++)a[i]+=b[i];
}
//a-=b;
void vector_diff(VECTOR a, CONST_VECTOR b, int n){
int i;
for(i=0;i<n;i++)a[i]-=b[i];
}

//a = a-b;
void vector_rdiff(VECTOR a, CONST_VECTOR b, int n){
int i;
for(i=0;i<n;i++)a[i]=b[i]-a[i];
}

//out = in1*in2; the size of in1 is n*c, the size of in2 is c*m
void matrix_mul(MATRIX out, CONST_MATRIX in1, CONST_MATRIX in2, int n, int c, int m){
int i,j,k;
for(i=0;i<n;i++)for(j=0;j<n;j++){
ftype sum=0.0;
for(k=0;k<n;k++){
sum+=in1[i][k]*in2[k][j];
}
out[i][j]=sum;
}
}

//out = M*in, where the size of 'M' is n*m and the size of 'in' is m
void matrix_mul_vector(VECTOR out, CONST_MATRIX M, CONST_VECTOR in, int n, int m){
int i,j;
for(i=0;i<n;i++){
ftype sum=0;
for(j=0;j<m;j++){
sum+=M[i][j]*in[j];
}
out[i]=sum;
}
}

//v[i]=c for all i
void vector_init_const(VECTOR v, ftype c, int n){
int i;
for(i=0;i<n;i++)v[i]=c;
}

//O[i][j]=0 for all (i,j)
void matrix_init_O(MATRIX O, int n, int m){
int i,j;
for(i=0;i<n;i++)for(j=0;j<m;j++)O[i][j]=0.0;
}

//extract the k-th column of matrix M (n rows) to vector out
void extract_matrix_column(VECTOR out, CONST_MATRIX M, int n, int k)
{
int i;
for(i=0;i<n;i++){
out[i]=M[i][k];
}
}
//Change the k-th column of matrix M (n rows) to vector in
void update_matrix_column(MATRIX M, const VECTOR in, int n, int k)
{
int i;
for(i=0;i<n;i++){
M[i][k]=in[i];
}
}
//M[i][j]=c for all (i,j)
void matrix_init_const(MATRIX M, ftype c, int n,int m){
int i,j;
for(i=0;i<n;i++)for(j=0;j<m;j++)M[i][j]=c;
}
//Square matrix E =diag{1,1,...,1}
void matrix_init_E(MATRIX E, int n){
int j;
matrix_init_O(E,n,n);
for(j=0;j<n;j++)E[j][j]=1.0;
}
//M=K; the size of matrix is n*m
void matrix_copy(MATRIX M, CONST_MATRIX K, int n,int m){
int i,j;
for(i=0;i<n;i++)for(j=0;j<m;j++)M[i][j]=K[i][j];
}
//c=w; for size of vector is n
void vector_copy(VECTOR v, CONST_VECTOR w, int n){
int i;
for(i=0;i<n;i++)v[i]=w[i];
}

void matrix_output(CONST_MATRIX M, int n,int m){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
printf("%g\t",M[i][j]);
}
printf("\n");
}
}
void vector_output(VECTOR v, int n){
int i;
for(i=0;i<n;i++)printf("%g\t",v[i]);
printf("\n");
}

int N, M;
VECTOR cn, sn;///Array to hold cos(k*Pi/(N+1)), sin(k*Pi/(N+1)), 1<=k<=N
VECTOR cm, sm;///Array to hold cos(k*Pi/(M+1)), sin(k*Pi/(M+1)), 1<=k<=M
MATRIX TN,TM;
void fini()
{
vector_free(cn);
vector_free(sn);
vector_free(cm);
vector_free(sm);
matrix_free(TN);
matrix_free(TM);
}

void init()
{
int i,j;
ftype mul=sqrt(2.0/(N+1));
ftype mul2=sqrt(2.0/(M+1));
cn=vector_alloc(N);
sn=vector_alloc(N);
cm=vector_alloc(M);
sm=vector_alloc(M);
TN=matrix_alloc(N,N);
TM=matrix_alloc(M,M);
for(i=0;i<N;i++){
cn[i]=cos((i+1)*M_PI/(ftype)(N+1));
sn[i]=sin((i+1)*M_PI/(ftype)(N+1));
}
for(i=0;i<M;i++){
cm[i]=cos((i+1)*M_PI/(ftype)(M+1));
sm[i]=sin((i+1)*M_PI/(ftype)(M+1));
}
for(i=0;i<N;i++)for(j=0;j<N;j++){
int index=(i+1)*(j+1);
int is_minus=1;
index%=2*(N+1);
if(index>N){
is_minus=-1;
index-=N+1;
}
if(index==0){
TN[i][j]=0;
}else{
TN[i][j]=sn[index-1]*mul*is_minus;
}
}
for(i=0;i<M;i++)for(j=0;j<M;j++){
int index=(i+1)*(j+1);
int is_minus=1;
index%=2*(M+1);
if(index>M){
is_minus=-1;
index-=M+1;
}
if(index==0){
TM[i][j]=0;
}else{
TM[i][j]=sm[index-1]*mul2*is_minus;
}
}
}

void TWODDST(MATRIX out, const MATRIX in)
{
int i;
VECTOR tmp1=vector_alloc(N);
VECTOR tmp2=vector_alloc(N);
for(i=0;i<N;i++){
matrix_mul_vector(out[i], TM, in[i], M, M);
}
for(i=0;i<M;i++){
extract_matrix_column(tmp1, out, N, i);
matrix_mul_vector(tmp2, TN, tmp1, N, N);
update_matrix_column(out, tmp2, N, i);
}
vector_free(tmp2);
vector_free(tmp1);
}

int zero_candidate(int x, int y){
if(x*2==N+1&&y*2==M+1)
return 1;
if(x*5==N+1&&y*5==3*(M+1))
return 1;
if(x*5==3*(N+1)&&y*5==M+1)
return 1;
return 0;
}
//Return nonzero when there's solution for equation.
int Solve(MATRIX x, const MATRIX init)
{
MATRIX tmp = matrix_alloc(N,M);
int i,j;
int failed=0;
int zero_count=0;
TWODDST(tmp, init);
for(i=0;i<N;i++)for(j=0;j<M;j++){
if(zero_candidate(i+1,j+1)){
if(fabs(tmp[i][j])>=ERROR){//No solution, this element must be 0.
failed=1;
}
tmp[i][j]=0.0;
zero_count++;
}else{
tmp[i][j]/=(2.0*cn[i]+1.0)*(2.0*cm[j]+1.0)-1.0;
}
}
if(failed)return 0;//No solution available;
TWODDST(x, tmp);
return 1;
}

int IsValidSolution(MATRIX x)
{
int i,j;
for(i=0;i<N;i++)for(j=0;j<M;j++){
if(fabs(x[i][j])>ERROR&&fabs(x[i][j]-1)>ERROR){
return 0;
}
}
return 1;
}

void GaussSolve(const MATRIX kmatrix, VECTOR r,int order)
{
int i,j,k;
MATRIX tmp=matrix_alloc(order,order);
for(i=0;i<order;i++)for(j=0;j<order;j++){
tmp[j][i]=kmatrix[i][j];
}
for(i=0;i<order;i++){
ftype f=tmp[i][i];
for(j=i;j<order;j++)
tmp[i][j]/=f;
r[i]/=f;
for(j=0;j<order;j++){
ftype div=tmp[j][i];
if(j==i)continue;
for(k=i;k<order;k++){
tmp[j][k]-=div*tmp[i][k];
}
r[j]-=div*r[i];
}
}
matrix_free(tmp);
}

void SolutionOutput(MATRIX x)
{
int i,j;
for(i=0;i<N;i++){
for(j=0;j<M;j++){
int v=(int)(x[i][j]+0.5);
printf("%d",v);
}
printf("\n");
}
}


  • 打赏
  • 举报
回复
mathe 2007-11-11
发现前面我写的判断等式
2*cos(k1*Pi/(n+1))/(1+2*cos(k1*Pi/(n+1))) = 2*cos((k2*Pi)/(m+1))
无解的代码写错了,实际上,对于很多m,n都是有解的。
比如4×4,4×9,4×19等都有解。
但是500以内,最多都只有3组解。所以在500以内,最差情况要穷举8种情况。(试验3次)
  • 打赏
  • 举报
回复
mathe 2007-11-11
通过http://topic.csdn.net/u/20071108/08/719928df-943e-4c4c-8c0a-0c50bedd3d02.html中的分析
可以知道,这道题目也可以用O(nmlog(n+m))的算法达到。
对于雷区最终和数据矩阵假设为a(i,j)
而每个格子用x(i,j)表示,0表示无雷,1表示有雷
分别用A和X表示a和x的二维离散正弦变换(也就是先各行做离散正弦变换,再各列做变换)
那么可以有
((2cos(i*PI/(n+1))+1)(2cos(j*PI/(m+1))+1)-1)*X(i,j)=A(i,j)
如果左边系数总不是0,马上就可以解出X(i,j)
不然,必然要求对应的A(i,j)也是0,这时,对应X(i,j)可以取任意值,这是一个可变参数。
根据我前面的一个分析,我们知道在m,n不超过500的范围内,最多只有m=n都是奇数的情况有可能有一项系数是0
也就是说,这个可变参数最多只有一个。
所以我们得到了x(i,j)的二维离散正弦变换,其中最多一个可变参数。
然后我们对X做逆变换,变换结果可以写成
u(i,j)+t*v(i,j)
其中t就是那个可变参数
而且矩阵v很特殊,它每个元素都不是0。
由于u(i,j)+t*v(i,j)总是0或1
我们只要任意选一个位置,分别让这个位置取0或1就可以得到一个t的值,
然后带入求出其他位置的值,如果对应值不是0和1,说明是非法解。
这个也正好检验了前面zgg提到的只需要蒙一次的过程,上面分析说明对于任何局面,我们最多需要蒙一次。
而最终的解也可以证明是唯一的。如果不唯一,那么说明存在两个不同的t:t1,t2使得
u(i,j)+t1*v(i,j)和u(i,j)+t2*v(i,j)都是0或1
也就是(t1-t2)*v(i,j)总是0,-1,1.
由于v(i,j)总是非0,t1!=t2,所以(t1-t2)*v(i,j)都只能是-1,1
也就是说,|v(i,j)|必须是常数
而矩阵v的值是有解析形式的,只有m和n都不超过2的时候,才会有|v(i,j)|是常数
而我们前面说过只有m=n而且是奇数时才出现待定系数。所以总共我们就得出m=n=1的这种特殊情况解不唯一(实际上这种情况的确解不唯一)
  • 打赏
  • 举报
回复
mathe 2007-11-11
所以最后的结论是
一般情况只有唯一解
如果m和n都是奇数,那么
((2cos(i*PI/(n+1))+1)(2cos(j*PI/(m+1))+1)-1)
中会有一项为0 (i=(n+1)/2, j=(m+1)/2)
如果m+1和n+1都是5的倍数,那么还有另外两项是0
(i=(m+1)/5, j=3*(n+1)/5 或 i=3*(m+1)/5, j=(n+1)/5)
最多有3个自由参数,也就是最多枚举8种情况就可以了。
  • 打赏
  • 举报
回复
mathe 2007-11-11
有一道关于正三十边形的对角线可将其为多少部分的题目,
关于这个题目,berkeley大学的Bjorn Poonen给出了一个公式,在其这篇文章中,他分析了所有形如
u1+u2+...+uk=0(其中u1,u2,...,uk都是1的单位根,也就是有某个整数hi使得ui^hi=1)
的解。
通过他的文章的结论,得知所有最多8项的这样的表达式中单位根的幂总是7,5,3,2或它们的乘积
而我上面的等式可以转化为长度为8的这样的和。
由于我已经搜索了500以内的范围,所以不会有其他解了。
也就是所有可能为0的系数已经全部得出。
  • 打赏
  • 举报
回复
mathe 2007-11-11
那个额外的解就是
(2*cos(Pi/5)+1)(2*cos(3*Pi/5)+1)=1.
  • 打赏
  • 举报
回复
mathe 2007-11-01
其实还有一个有意思的结论.
如果det(g(B,I+B))是奇数
那么我们只要知道每个格子周围的雷的总数的奇偶性就可以唯一确定结果了.
比如对于上面列出的4*5的例子,可以算出det(g(B,I+B))是奇数 (模2计算就可以了)
所以对于这个例子,我们只要知道雷数的奇偶性就可以唯一确定结果了.
其实只知道雷的总数的奇偶性的问题同另一个问题(关灯游戏 http://blog.csdn.net/mathe/archive/2006/08/30/1143634.aspx )
就几乎一模一样了,除了每次关灯影响的灯的数目不同.
实际上,这道题目的解法的思想也来源于那道题目,只是在那里,所有东西都是模2运算,计算更加方便.
  • 打赏
  • 举报
回复
mathe 2007-11-01
是的,我后面都已经是按8连通来推理的.
按照我上面现在给出的结论,
在m,n不超过500的情况下面, 如果m,n至少有一个是偶数,那么把所有的约束写成等式来解方程组,方程组的解必然是唯一的.
比如上面4*5的情况,有20个格子,每个格子可以对应一个变量,如果没有雷就是0,有雷就是1.
那么每个格子周围雷的数目就是一条等式.
这样我们就得到一个20阶线性方程组,解这个方程组就可以了.
当然,直接这样解方程组是个时间复杂度为O((mn)^3)的问题.我上面的讨论是说,复杂度可以降低到O((m+n)^4)
  • 打赏
  • 举报
回复
zgg___ 2007-10-31
接着上面的说:
如果m和n中有一个是偶数或都是偶数,那么解貌似是唯一的。
如果m和n都是奇数,那么解可能不是唯一的,但是貌似只需要蒙一次就够了。
下面是3乘3时,需要蒙一次的例子:
010
121
010
  • 打赏
  • 举报
回复
zgg___ 2007-10-31
lz在4层所说的“数字是他周围雷的数目”的条件,可以理解为:周围的雷,且不包括本格的雷,也就是只计算它周围的8个格的地雷数。如果是这样,答案是不是唯一的呢?也就是“无需猜测就可以标定所有的雷”呢?
  • 打赏
  • 举报
回复
pavelalex 2007-10-31
TO mathe:
每个格子的数是它周围八个区域的雷的总数,但不包括他自己在内。
eg:
角上的数字就是:0-3
边的是:0-5
其余就是:0- 8

这是雷区的一个例子:
0 0 0 0 0
0 0 1 0 0
0 1 0 0 2
0 0 0 3 1


  • 打赏
  • 举报
回复
mathe 2007-10-31
用计算机验算,设置计算误差为10^(-6),
对于500以内的m和n,没有出现ii)中等式成立的.看来ii)中等式很可能永远不成立
  • 打赏
  • 举报
回复
mathe 2007-10-31
另外还有n+1被3整除的情况,我们判断det(g(B,I+B))是否等于0,
只要判断对于B的所有特征值u,g(u,1+u)是否都不是0
对于1+u=0(也就是特征值-1),结果就是f(m,-1)展开的第一项,当然不是0
而对于1+u<>=0,g(u,1+u)=f(m,u/(2*(1+u))),所以我们实际上还是可以用判断式
2*cos(k1*Pi/(n+1))/(1+2*cos(k1*Pi/(n+1))) = 2*cos((k2*Pi)/(m+1))来判断.

所以判断方程中矩阵是否可逆,我们可以用如下方法.
i)如果m,n都是奇数,不可逆.
ii)不然,对于x=cos(k*Pi/(n+1)) (k=1,2,...,n)
计算sin((m+1)arccos(x/(1+2*x))),如果这个值为0,矩阵不可逆
不然,矩阵可逆.
当然第二步只能近似计算.
  • 打赏
  • 举报
回复
加载更多回复
相关推荐
发帖
数据结构与算法
加入

3.2w+

社区成员

数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
申请成为版主
帖子事件
创建了帖子
2007-10-29 02:08
社区公告
暂无公告