查看: 2152| 回复: 12
跳转到指定楼层
上一主题 下一主题
收起左侧

[其他] 请教一道算法题

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
本帖最后由 iamczh 于 2021-3-2 20:29 编辑

给定一个二维数组,其中的1只可以变为0, 0只可以变为1 更改一个元素的时候,上下左右连同自己都会翻转。问最少几次可以翻转为全部都是1。感觉除了暴力没有什么思路,有其他解法吗?


case 1:output: 1
1011       1111
0001 ->  1111
1011      1111

翻转(1,1)

case 2: output: 4

1111       11OO       111O       1111       1111
1O11 - > 1O1O - >  11O1 - > 111O - > 1111
1111       1111        11O1       11OO      1111
  
依次翻转(0,3) -> (1,2) -> (3,2) -> (2,3)



上一篇:聊一下Bamboo vs Jenkins 的区别
下一篇:[其他] Mock Interview(Pramp或zoom都行)一起模拟面试(算法或者system design?)
全局:
本帖最后由 不知道小帅 于 2021-3-3 00:10 编辑

暴力是暴力,但是可以稍微聪明一点的暴力。这个题目的话,bfs/dfs都可以做。bfs的话就是说直接从目标状态开始,然后bfs,算步数。中间需要一些hashing,把每个状态hash一下。bfs的话有一种优化的方法,就是用双向bfs(bidirectional bfs),大概可以优化到根号下原先bfs的时间复杂度,也是指数级别。
dfs的话,其实是可以比纯粹暴力优化一些的。枚举的顺序非常重要。不管怎么说,这个题目都是NP-complete问题,所以基本上枚举就是正解了。
dfs的话,可以通过控制搜索顺序来达到更好的时间复杂度(虽然不管怎么好都是exponential)。

评分

参与人数 1大米 +1 收起 理由
YBC人生 + 1 赞一个

查看全部评分

回复

使用道具 举报

全局:
更确切的说法其实是,这个A的逆叫做有限整数域Z_2意义下的逆。所谓有限整数域Z_2,就是说大于1的元素的操作不存在,我们认为 2=0, 1=-1
因为A是个方阵,这个逆总存在。
回复

使用道具 举报

推荐
twtypsj 2021-3-4 14:05:50 | 只看该作者
全局:
本帖最后由 twtypsj 于 2021-3-4 14:20 编辑

好像以前玩过一个类似的游戏,当时不知道是不是所有的组合都可以成功。

不过大概理解了意思,写了一下代码,不知道是不是所有的case都可以cover

欢迎讨论


  1. [i]#include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <queue>
  5. #include <unordered_map>
  6. #include <unordered_set>
  7. #include <algorithm>
  8. using namespace std;

  9. string flip(string input, int y, int x, int m, int n)
  10. {
  11.     auto change = [&](int i, int j)
  12.     {
  13.         if(i<0||i>=m||j<0||j>=n) return;
  14.         input[i*n+j]= input[i*n+j]=='0'?'1':'0';
  15.     };
  16.     change(y,x);
  17.     change(y+1,x);
  18.     change(y-1,x);
  19.     change(y,x+1);
  20.     change(y,x-1);
  21.     return input;
  22. }
  23. vector<string> findMoves(string input, int m, int n)
  24. {
  25.     string target(m*n, '1');
  26.     if(target == input) return {input};
  27.     queue<string> q;
  28.     q.push(input);
  29.     unordered_set<string> visited{input};
  30.     unordered_map<string,string> path;

  31.     while(!q.empty())
  32.     {
  33.         int size = q.size();
  34.         while(size--)
  35.         {
  36.             string f = q.front(); q.pop();
  37.             for(int i=0; i<m; ++i) for(int j=0;j<n; ++j)
  38.             {
  39.                 string next = flip(f,i,j,m,n);
  40.                 if(next == target)
  41.                 {
  42.                     vector<string> res{target};
  43.                     string str = f;
  44.                     while(path.count(str))
  45.                     {
  46.                         res.push_back(str);
  47.                         str = path[str];
  48.                     }
  49.                     res.push_back(input);
  50.                     reverse(res.begin(), res.end());
  51.                     return res;
  52.                 }
  53.                 if(visited.count(next)) continue;
  54.                 visited.insert(next);
  55.                 path[next] = f;
  56.                 q.push(next);
  57.                
  58.             }
  59.         }
  60.     }
  61.     return {};
  62. }
  63. int findMoves(vector<vector<int>> input)
  64. {
  65.     string str;
  66.     for(int i=0;i<(int)input.size();++i) for(int j=0;j<(int)input[i].size();++j) str+=input[i][j]+'0';
  67.     auto res = findMoves(str, (int)input.size(), (int)input[0].size());
  68.     for(auto& i : res) cout << i << " ";
  69.     cout << endl;
  70.     return res.size()-1;
  71. }



  72. int main()
  73. {
  74.     vector<vector<int>> matrix{
  75.         {1,1,1,1},
  76.         {1,0,1,1},
  77.         {1,1,1,1},
  78.         };
  79.     cout << findMoves(matrix) << endl;
  80.     return 0;
  81. }
  82. [i][i]
  83. [i]
复制代码
[/i][/i][/i][/i]

评分

参与人数 1大米 +1 收起 理由
blackrose + 1 赞一个

查看全部评分

回复

使用道具 举报

全局:
暴力是指?
回复

使用道具 举报

全局:
这是算法题还是puzzle呀!
回复

使用道具 举报

🔗
wisdompeak2 2021-3-3 03:49:59 | 只看该作者
全局:
本帖最后由 wisdompeak2 于 2021-3-3 03:53 编辑

你可以把这道题当作解线性方程组,求解Ax=T。你需要有点线性代数的思维。
x是一个列向量,长度是m = axb,其中a,b是原矩形的维度。x的每一个元素表示棋盘的一个格子的动作(1表示翻转,0表示不翻转)
A是状态转移矩阵,维度是mxm,Ax的结果也是一个长度为m的列向量,表示原棋盘状态x经过指定的翻转操作后,得到的新棋盘状态。
A的元素可以通过规则定义来构造。
如果T是最终状态,那么x可以通过A的逆乘以T得到。注意x可能无解。另外x的解的每个元素可能大于1,翻转多余两次是没有意义的,需要再对x mod 2.

给了个3x3的解:
  1. import numpy as np
  2. A = np.array([
  3.         [1,1,0,1,0,0,0,0,0],
  4.         [1,1,1,0,1,0,0,0,0],
  5.         [0,1,1,0,0,1,0,0,0],
  6.         [1,0,0,1,1,0,1,0,0],
  7.         [0,1,0,1,1,1,0,1,0],
  8.         [0,0,1,0,1,1,0,0,1],
  9.         [0,0,0,1,0,0,1,1,0],
  10.         [0,0,0,0,1,0,1,1,1],
  11.         [0,0,0,0,0,1,0,1,1]],'float')
  12. A = np.transpose(A)

  13. iA = np.linalg.inv(A)*7
  14. iA.astype('int') % 2

  15. S = np.array([[1,1,1,1,1,1,1,1,1]])
  16. S = np.transpose(S)
  17. T = np.array([[0,0,0,0,0,0,0,0,0]])
  18. T = np.transpose(T)

  19. ret = np.dot(iA,T-S)
  20. ret = np.rint(ret)
  21. ret = ret % 2
  22. print(ret)
复制代码


顺便说一句,Ax=T的解可能有无数个。但通过x = A的伪逆乘以T 得到的解,是所有解中L2范数最小的,符合本题的要求(最少的翻转次数)。
总之,你想把它当作数学题的话,那就是超纲了。
回复

使用道具 举报

全局:
wisdompeak2 发表于 2021-03-02 11:49:59
你可以把这道题当作解线性方程组,求解Ax=T。你需要有点线性代数的思维。
x是一个列向量,长度是m = axb,其中a,b是原矩形的维度。x的每一个元素表示棋盘的一个格子的动作(1表示翻转,0表示不
L-2 norm不代表就是总和最小吧,应该是L-1 norm才代表吧。感觉这个很难严格证明这个解一定就是最优。
回复

使用道具 举报

全局:
很有意思的一个puzzle.
Lights out puzzle曾经是个电子游戏。这有个试玩版的:https://www.geogebra.org/m/JexnDJpt#material/KArehWn8

假设是个m乘n矩阵,如果其中m或者n的一个是比较小的数字,比如m<=10, 可以有状态压缩DP的解法。
对一般情况,楼上也有提到用矩阵求解,这里有个详细的说明 https://mathworld.wolfram.com/LightsOutPuzzle.html
这个算法可以求出是否能有一个解满足要求,但很多情况下不止有一个解。

然后应该需要在solution space里找support最小的解,即L0-optimization。因为这个题里只能选0和1,其实按L0, L1, L2,...去优化貌似都是等效的。
显然solution space不是convex的,怎么去整数优化就涉及到我的知识盲区了。
等优化大佬出场。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表