工做區的顏值選擇(簡單)

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

相關文章
相關標籤/搜索