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

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

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

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

给的时间是5000ms,所以可以接收几十亿或者百亿级别的数据。

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

先发自己的错误代码:

#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代码

#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; }

总结:

简单模式下一道水题。DFS和BFS我是会了忘又忘了会,感觉原因是因为只记住了它的行为模式,代码还是打的少。

要多打代码,把各种情况分类,以模板化的方式来针对不同的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

猜你喜欢

转载自www.cnblogs.com/worldcreator-zh/p/10508142.html