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