工做区的颜值选择(简单)

https://nanti.jisuanke.com/t/A1012ios

计蒜课上的练习题,只说简单版本的作法。算法

最大数据为61个k的值,2*3=6个位置,枚举法共用61^(指数)6=大约500亿,在百亿级别,且能够对其用当前sum>ans(最小值)时回溯剪枝,大大下降运算量。函数

给的时间是5000ms,因此能够接收几十亿或者百亿级别的数据。从新测速以后发现个人电脑10亿for循环大概两秒,可是本题k=30时测到的运行时间是大概几百ms到2000不等,证实剪枝确确实实的减小了很是多的运算,至少下降到了10亿如下。想一想解答树的关系也可想而知,第n层数量有2k^n种可能。当k=30的时候,下一层单一层结点的数量就是上边全部结点数量和的60倍(其实也就是上一层的60倍,再往上的结点根本少到不够加),因此!剪枝很是有必要!!!学习

采用DFS深度优先搜索进行遍历。大数据

先发本身的错误代码:spa

#include<iostream> #include<algorithm> #include<string.h>
#define maxn 5
#define rep(i,n,t) for(int i=(n);i<(t);i++)
#define mms(a,b) memset(a,(b),sizeof(a))
int fs[maxn][maxn]; int wf[maxn][maxn];int ks[maxn][maxn]; int n, m, k; int ans; using namespace std; bool cheak(int i, int j) { if (i < n&&i>=0 && j < m&&j>=0) return true; return false; } void DFS(int i,int j,int sum ) { if (i == n) { ans = min(ans, sum); return; }; if (i >= n && i < 0 && j < 0 && j >= m) return; rep(l, -k, k + 1) { ks[i][j] = l; cout << &sum<<endl; sum += (abs(l + i + 1 + j + 1) ^ fs[i][j])*wf[i][j]; if (cheak(i - 1,j)) sum += abs(ks[i - 1][j] + ks[i][j]); if (cheak(i , j-1)) sum += abs(ks[i][j-1] + ks[i][j]); cout << sum << endl; if(j<m-1)DFS(i, j + 1, sum); else DFS(i + 1, 0, sum); } } int main() { cin >> n >> m >> k; rep(i, 0, n) rep(j, 0, m) cin >> fs[i][j]; rep(i, 0, n) rep(j, 0, m) cin >> wf[i][j]; rep(i, 0, n) rep(j, 0, m) ans += abs((i + 1 + j + 1) ^ fs[i][j])*wf[i][j]; DFS(0, 0, 0); cout << ans;
   return 0; }
//为何不对:在DFS递归中每次进行sum数值的更新,想法是每一层有当前本身的sum,与ans比较后回溯到上一层时, //sum会读到上一层的sum值,而后继续带入下一个k进行下一轮调用。结果在更新时出现了问题,忘了考虑每次都会进行数值更新 //而我所学习的博客博主作法是用一个函数(传值)来处理sum数值的更新,返回值也是传值返回计算结果,并用这个返回值做为 //调用下一层循环的参数。这样致使每层中的sum只是用做存储本层时的sum状态,不作运算。避免了我乱七八糟的问题。 //

 

 

 

ac代码.net

#include<iostream> #include<algorithm> #include<string.h>
#define maxn 5
#define rep(i,n,t) for(int i=(n);i<(t);i++)
#define mms(a,b) memset(a,(b),sizeof(a))
int fs[maxn][maxn]; int wf[maxn][maxn]; int ks[maxn][maxn]; int n, m, k; int ans; using namespace std; bool cheak(int i, int j) { if (i < n&&i >= 0 && j < m&&j >= 0) return true; return false; } int updata(int i, int j, int sum)//sum的更新应于当前层数递归参数更新以后,而且下一层递归调用以前
{ sum += (abs(ks[i][j] + i + 1 + j + 1) ^ fs[i][j])*wf[i][j]; if (cheak(i - 1, j)) sum += abs(ks[i - 1][j] + ks[i][j]); if (cheak(i, j - 1)) sum += abs(ks[i][j - 1] + ks[i][j]); return sum; } int DFS(int i, int j, int sum)//DFS写成int型
{ if (sum >= ans) return 0;//剪枝
    if (i == n) { ans = min(ans, sum); return 0; }; rep(l, -k, k + 1) { ks[i][j] = l; if (j<m-1)DFS(i, j + 1, updata(i,j,sum));//0~倒数第二个元素的脚标。
        else if(j==m-1)DFS(i + 1, 0, updata(i,j,sum));//当走到行末的时候应该调用下一行行首
 } } int main() { cin >> n >> m >> k; rep(i, 0, n) rep(j, 0, m) cin >> fs[i][j]; rep(i, 0, n) rep(j, 0, m) cin >> wf[i][j]; rep(i, 0, n) rep(j, 0, m) ans += abs((i + 1 + j + 1) ^ fs[i][j])*wf[i][j]; DFS(0, 0, 0); cout << ans;
  return 0; }

总结:code

简单模式下一道水题。DFS和BFS我是会了忘又忘了会,感受缘由是由于只记住了它的行为模式,代码仍是打的少。blog

要多打代码,把各类状况分类,以模板化的方式来针对不一样的DFS和BFS状况来写才是王道,这样效率才高,固然理解算法的行为是前提。递归

好比这道题就是一个“无标记,求最优型”(我瞎起的)。就要套用这种函数做为数据更新处理,参数只作当前递归层状态的递归模式。

接下来几天我准备仔细的从新学一遍DFS和BFS再作相应练习来概括总结。再开一篇来做为分类和模板。争取把之后遇到的都收集起来归归类。

十分感谢这位大佬规范的代码,从中学到了好多好多!!!!!https://blog.csdn.net/mengzhengnan/article/details/46958273

十分感谢这位大佬规范的代码,从中学到了好多好多!!!!!https://blog.csdn.net/mengzhengnan/article/details/46958273

十分感谢这位大佬规范的代码,从中学到了好多好多!!!!!https://blog.csdn.net/mengzhengnan/article/details/46958273

相关文章
相关标签/搜索