记录一下自己的笔试的代码题


第一题

给定n段内存,起始地址加偏移地址,m个操作,操作a表示在a-2到a+2区间增加可用内存,-a表示在a-2到a+2区间减少可用内存。内存范围在0-4096之间。求操作后的可用内存地址有哪些。(需要合并重叠内存,并从低地址到高地址排序)

    //合并重叠内存
    vector<vector<int>> combineRAM(vector<vector<int>> &v){
        vector<vector<int>> ret;
        vector<int> tmp = v[0];
        for(int i = 1; i < v.size(); ++i){
            if(tmp[1] >= v[i][0] && tmp[1] <= v[i][1] ){ //重叠则合并
                tmp[1] = v[i][1];
            } else if(tmp[1] < v[i][0]){    //未重叠,则添加到返回数组里
                if(tmp[0] != tmp[1]) ret.emplace_back(tmp);
                tmp = v[i];
            } else if(tmp[1] > v[i][1]){
                continue;
            }
        }
        if(tmp[0] != tmp[1]) ret.emplace_back(tmp);
        return ret;
    }

    vector<vector<int>> ramManager(vector<vector<int>> input, vector<int> &options, int n, int m){
        vector<vector<int>> v(n, vector<int>(2));
        for(int i = 0; i < n; ++i){
            v[i][0] = input[i][0];
            v[i][1] = input[i][0] + input[i][1];
        }
        for(int i = 0; i < m; ++i){
            int t = options[i];     //取出当前操作
            if(t > 1 && t < 4095){
                vector<int> p = {t-2, t+2};
                v.emplace_back(p);
            } else if(t < 2 && t >= 0) {
                vector<int> p = {0, t + 2};
                v.emplace_back(p);
            } else if(t > 4094 && t <= 4096){
                vector<int> p = {t-2, 4096};
                v.emplace_back(p);
            } else {                //操作为负数,则是减少可用内存
                int l = abs(t) - 2;
                int r = abs(t) + 2;
                if(l < 0) l = 0;
                if(r > 4096) r = 4096;
                for(int j = 0; j < v.size(); ++j){
                    if(l <= v[j][0] && r > v[j][0]){
                        v[j][0] = r;
                        break;
                    } else if(l < v[j][1] && r > v[j][1]){
                        v[j][1] = l;
                        break;
                    } else if(l >= v[j][0] && r <= v[j][1]){
                        int tl = v[j][0], tr = v[j][1];
                        if(v[j][0] != l) v[j][1] = l;
                        if(v[j][1] != r){
                            vector<int> p = {r, tr};
                            v.emplace_back(p);
                        }
                        break;
                    }
                }
            }
        }
        sort(v.begin(), v.end());       //排序
        return combineRAM(v);           //返回合并后的内存
    }

首先转换为内存区间来表示。读取指令,当内存增加时,直接将新增内存块添加到列表里,而减少内存时,寻找当前空闲内存是否有和删除区间重叠的地方,如果没有则不删除,如果有,删除重叠部分,若增加了内存块数量,则修改原内存的区间,并在末尾添加新增的内存块。经过排序后,合并重叠内存部分,并返回。

第二题

给一张N*M的图,图里每个格子都有个高度,每次移动只能在高度差T内,问从0,0开始,有3次机会可以无视高度差移动,到最右下角最短需要多少步。


    vector<int> result;
    void backtracking(vector<vector<int>> &vec, vector<vector<bool>> path, int i, int j, int cnt, int bo, int &dif, int last_v){
        if( i  >= vec.size()  - 1 && j >= vec[0].size() - 1){
            result.push_back(cnt);
            return;
        }
        path[i][j] = true;
        if(abs(vec[i][j] - last_v) > dif) bo++;
        if(bo > 3) return;
        cnt++;
        if(i + 1 <= vec.size() - 1 && !path[i+1][j]) backtracking(vec, path, i+1, j, cnt, bo, dif, vec[i][j]);
        if(j + 1 <= vec[0].size() - 1 && !path[i][j+1]) backtracking(vec, path, i, j + 1, cnt, bo, dif, vec[i][j]);
        if(i - 1 >= 0 && !path[i-1][j]) backtracking(vec, path, i-1, j, cnt, bo, dif, vec[i][j]);
        if(j - 1 >= 0 && !path[i][j-1]) backtracking(vec, path, i, j-1, cnt, bo, dif, vec[i][j]);
    }

    int main(){
        int n, m, diff;
        cin >> n >> m >> diff;
        vector<vector<int>> vec(n, vector<int>(m, 0));
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                cin >> vec[i][j];
            }
        }
        vector<vector<bool>> path(n, vector<bool>(m, false));
        path[0][0] = true;
        int bo = 0;
        if(1 <= n - 1) backtracking(vec, path, 1, 0, 1, 0, diff, vec[0][0]);
        if(1 <= m - 1) backtracking(vec, path, 0, 1, 1, 0, diff, vec[0][0]);
        if(result.size() == 0){
            cout << -1;
            return 0;
        }
        sort(result.begin(), result.end());
        cout<<result[0];
        return 0;
    }

dfs寻找到满足条件的所有路径的步数,排序后取最小步数。(其实不用排序,直接循环一遍找最小值也可以)

第三题

n号港口,每个港口有一个停靠花费和到下一个港口的距离。一艘船每次只能走N的距离,寻找花费最小的路径走到目的地,输出走过的路径,若花费相同,输出序列靠前的路径,目的地不在给出港口中。


    void dfs(vector<vector<int>> &paths, vector<int> &cost, vector<int> path, vector<int> &val, vector<int> &dist, int i, int c, int N){
        if(i < val.size()){
            path.emplace_back(i);
            c += val[i];
            int p = 0;
            for(int j = i; j < val.size(); ++j){
                p += dist[j];
                if(p <= N){
                    dfs(paths, cost, path, val, dist, j+1, c, N);
                } else return;
            }
        } else {
            paths.emplace_back(path);
            cost.emplace_back(c);
        }
    }

    vector<int> findPath(int n, vector<int> &val, vector<int> &dist, int N){
        vector<vector<int>> paths;
        vector<int> path;
        vector<int> cost;
        for(int i = 0; i < n ; ++i){
            if(dist[i] > N) return {-1};
        }
        dfs(paths, cost, path, val, dist, 0, 0, N);
        int minCost = INT32_MAX;
        for(int i = 0; i < cost.size(); ++i){
            minCost = min(minCost, cost[i]);
        }
        for(int i = 0; i < cost.size(); ++i){
            if(cost[i] == minCost){
                path = paths[i];
                break;
            }
        }
        return path;
    }

    int main(){
        int n;
        cin>>n;
        vector<int> val(n), dist(n);
        for(int i = 0; i < n; ++i){
            cin>>val[i];
        }
        for(int i = 0; i < n; ++i){
            cin>>dist[i];
        }
        int N;
        cin>>N;
        vector<int> path = findPath(n, val, dist, N);
        for(int i = 0; i < path.size(); ++i){
            cout<<path[i];
            if(i != path.size()-1) cout<<' ';
        }
        return 0;
    }

使用dfs搜索,找到满足条件的所有路径,取第一个消耗最小的路径。