首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 关于给数扫雷的算法 [已结帖,结帖人:pavelalex]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • pavelalex
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 结帖率:
    发表于:2007-10-29 14:08:24 楼主
    已知把雷区的雷布好了,每个格子数字都填好(可见),怎么通过这些数字把雷找出来
    一起研究一下算法。
    20  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zgg___
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-29 15:11:461楼 得分:0
    那么地雷上填什么数字呢?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • huangzhtao
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-29 16:48:102楼 得分:0
    这个我以前做过.假设以1代表有雷,0代表没雷,输入存入一个N*N的数组中,程序开始时从(0,0)元素开始,判断它的左上,上,右上,右,右下,下,左下,左的8个方向上有没有一,用一个变量记录,有一个1则加1,判断完后存入对应位置,直到最后一个,记得每个元素改变时初始化记录变量为0.
    为了在处理雷区上,下,左,右边界时的简便,可以在输入雷区矩阵是,在外围加一圈0,表示无雷,使得边界的处理和中间的处理一样.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • huangzhtao
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-29 16:48:323楼 得分:0
    这个我以前做过.假设以1代表有雷,0代表没雷,输入存入一个N*N的数组中,程序开始时从(0,0)元素开始,判断它的左上,上,右上,右,右下,下,左下,左的8个方向上有没有一,用一个变量记录,有一个1则加1,判断完后存入对应位置,直到最后一个,记得每个元素改变时初始化记录变量为0.
    为了在处理雷区上,下,左,右边界时的简便,可以在输入雷区矩阵是,在外围加一圈0,表示无雷,使得边界的处理和中间的处理一样.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • pavelalex
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 08:33:114楼 得分:0
    说明一下,数字是他周围雷的数目
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 11:31:115楼 得分:0
    模拟手工解法是一种方法.直接搜索也是一种方法.最好是结合两种方法
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • pavelalex
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 12:31:486楼 得分:0
    楼上的能不能说清楚一点
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • NowCan
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 13:10:497楼 得分:0
    有时还需要一些猜测的。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • kaishui_gu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 13:33:298楼 得分:0
    看起来挺难的,关注
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • huangzhtao
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 14:40:419楼 得分:0
    哦,是我考虑简单了,这个算法还没想出来.
    是不是这样的话会有多种解?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-30 15:00:0010楼 得分:0
    当然可以不唯一,不如2*2的雷区
    1 1
    1 1
    有4个解。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zgg___
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 11:24:2211楼 得分:0
    lz在4层所说的“数字是他周围雷的数目”的条件,可以理解为:周围的雷,且不包括本格的雷,也就是只计算它周围的8个格的地雷数。如果是这样,答案是不是唯一的呢?也就是“无需猜测就可以标定所有的雷”呢?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zgg___
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 12:43:4012楼 得分:0
    接着上面的说:
    如果m和n中有一个是偶数或都是偶数,那么解貌似是唯一的。
    如果m和n都是奇数,那么解可能不是唯一的,但是貌似只需要蒙一次就够了。
    下面是3乘3时,需要蒙一次的例子:
    010
    121
    010
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 13:50:0213楼 得分:0
    to zgg__,
    我刚才还真得出了你这样的结论,不过后来发现看错了.
    对于m*n阶雷区
    我们记I为n阶单位矩阵
    B为一个n阶矩阵,所有同主对角线相邻的位置是1(不包含主对角线),其余位置都是0,比如对于n=4,B如下
    0100
    1010
    0101
    0010
    那么,原题目写成矩阵形式,所有方程系数构成如下m*n阶矩阵
    B  I+B 0  0 ... 0
    I+B  B I+B 0 ... 0
    0  I+B B I+B ...0   
    ..................
    ...........0 I+B B
    当然如果这个方阵可逆,那么问题的解唯一.
    记f(n,x)为n阶第二类切皮雪夫多项式(http://mathworld.wolfram.com/ChebyshevPolynomialoftheSecondKind.html)
    f(0,x)=1,
    f(1,x)=2x
    f(2,x)=4x^2 - 1
    另多项式:
    g(a,b)=f(m,a/(2b))*b^m
    那么上面矩阵同矩阵
    g(B,I+B)可逆性相同.
    也就是我们只要判断g(B,I+B)是否可逆就可以判断问题的解是否唯一了.
    如果题目改成我开始理解的样子,也就是周围理解成只有上下左右,那么上面分析中的I+B替换成I就可以了.
    对于m=1, g(a,b)=a, 所以g(B,I+B)=B=0 不可逆.实际上1*1的情况解就是不唯一的.
    对于m=2, g(a,b)=a^2-b^2, g(B,I+B)=-I-2B,通过切皮雪夫多项式的行列式形式可以知道
        det(g(B,I+B))=(-2)^n *f(n,1/4),
    通过切皮雪夫多项式的三角函数形式可以知道上面值非0.
    所以对于两行或两列的情况解都唯一.
    对于m=3, g(a,b)=a^3-2ab^2, g(B,I+B)=B^3-2B(I+B)^2=-2B-4B^2-B^3
      这个就比较难分析了.但是我们知道 B|g(B,I+B)
    但是det(B)=f(n,0)在n为奇数的时候是0.
    实际上,对于m和n都是奇数的情况,总是有B|g(B,I+B),而且det(B)=f(n,0)=0,所以det(g(B,I+B))=0
    也就是说,我们证明了在m,n都是奇数的情况,上面方程不可逆,解可能不唯一(但是没有证明解必然不唯一,毕竟挖雷中要求所有数字都是0,1,这个解方程是无法限制的).
    但是对于m,n至少有一个数是偶数时,我们还没有很好的结果.

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 14:11:5114楼 得分:0
    我们再考虑n+1不被3整除的情况
    由于det(I+B)=f(n,1/2),根据切皮雪夫多项式的三角函数形式可以知道这个值只有再3|n+1时为0
    所以n+1不被3整除时,I+B可逆,这时
    det(g(B,I+B))=det((I+B)^m)*det (f(m, 1/2*B*(I+B)^(-1)))
    上面第一项非0,而对于第二项,如果对于B的某个特征值u
      f(m,1/2*u/(1+u))=0,那么它为0,不然必然非0.
    根据切皮雪夫多项式的三角函数:设x=cos(t),那么f(n,x)=sin((n+1)t)/sin(t)
    得到使f(n,x)=0的x为cos(k*Pi/(n+1))
    所以B的所有特征值是2*cos(k*Pi/(n+1))
    所以只有对于存在k1,k2使得2*cos(k1*Pi/(n+1))/(1+2*cos(k1*Pi/(n+1))) = 2*cos((k2*Pi)/(m+1))
    的情况下,上面第二项才为0.
    不过分析对于什么样的m,n上面式子成立也是挺难的,不过计算机验算很简单.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 14:13:5615楼 得分:0
    上面的分析过程给出了一个这道题目在解唯一时比较有效的解法
    就是解方程,方程对应矩阵是
    B      I+B  0    0  ...  0
    I+B    B  I+B  0  ...  0
    0      I+B  B  I+B  ...0         
    .....................
    .................0  I+B  B
    这样的方程可以通过追赶发计算,时间复杂度为O((n+m)^4)
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 14:35:3516楼 得分:0
    另外还有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,矩阵不可逆
    不然,矩阵可逆.
    当然第二步只能近似计算.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 15:06:2217楼 得分:0
    用计算机验算,设置计算误差为10^(-6),
    对于500以内的m和n,没有出现ii)中等式成立的.看来ii)中等式很可能永远不成立
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • pavelalex
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-10-31 20:12:2718楼 得分:0
    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-11-01 07:50:1519楼 得分:0
    是的,我后面都已经是按8连通来推理的.
    按照我上面现在给出的结论,
    在m,n不超过500的情况下面, 如果m,n至少有一个是偶数,那么把所有的约束写成等式来解方程组,方程组的解必然是唯一的.
    比如上面4*5的情况,有20个格子,每个格子可以对应一个变量,如果没有雷就是0,有雷就是1.
    那么每个格子周围雷的数目就是一条等式.
    这样我们就得到一个20阶线性方程组,解这个方程组就可以了.
    当然,直接这样解方程组是个时间复杂度为O((mn)^3)的问题.我上面的讨论是说,复杂度可以降低到O((m+n)^4)
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-11-01 08:22:5420楼 得分:0
    其实还有一个有意思的结论.
    如果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-11 07:27:2221楼 得分:20
    通过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 12:41:3522楼 得分:0
    发现前面我写的判断等式
    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 13:16:5123楼 得分:0
    那个额外的解就是
    (2*cos(Pi/5)+1)(2*cos(3*Pi/5)+1)=1.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-11-11 15:50:2124楼 得分:0
    有一道关于正三十边形的对角线可将其为多少部分的题目,
    关于这个题目,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 16:04:2925楼 得分:0
    所以最后的结论是
    一般情况只有唯一解
    如果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-12 14:52:4726楼 得分:0
    C/C++ code
    #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-12 14:53:2127楼 得分:0
    C/C++ code
    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 14:56:4028楼 得分:0
    例子:
    输入:
    2 4
    2 1 2 0
    1 2 2 1
    (第一行代表输入是两行4列)
    输出:
    Solution 1:
    0101
    1000
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-11-12 17:40:1029楼 得分:0
    测试发现代码有两个BUG:
    i)AllSolutions()
    C/C++ code
    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()
    C/C++ code
    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
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • pavelalex
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-11-14 10:51:2830楼 得分:0
    math,真的太感谢了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mathe
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-11-15 07:59:4631楼 得分:0
    构造了一个有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
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • wjlsmail
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2007-11-21 13:14:0232楼 得分:0
    Mark, interest......
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • leinad2009
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2009-03-11 23:52:0833楼 得分:0
    学习!!!
    修改 删除 举报 引用 回复