GithubHelp home page GithubHelp logo

wisenetwork's Introduction

WiseNetwork

极简网络

wisenetwork's People

Contributors

mengxh1990 avatar

Watchers

 avatar  avatar

wisenetwork's Issues

可信认证

回溯算法

基本描述

leetcode定义
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 “回溯” 返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 “回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。

回溯算法的基本**是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

与递归,DFS关系
回溯算法是个**,回溯法的实现方法有两种:递归和递推(也称迭代,非递归)。一般来说,一个问题两种方法都可以实现,只是在算法效率和设计复杂度上有区别。
与DFS的整体过程是一致的,都是一条路走到底,不撞南墙不回头。回溯算法是枚举,枚举的方式是深度优先搜索,回溯算法需要在深度优先搜索的同时,把临时路径一直传递下去。
回溯算法三元素

  1. 选择。对于每个特定的解,每一步怎么构建,有多个选择,按照某种顺序依次尝试当前的每个选择,一般是通过多个if或者for循环来排列。
  2. 条件。对于每一个选择,只有符合条件才能继续向前扩展,如果不符合条件,就要回溯。
  3. 结束。当到达一个特定结束条件时,一个解就出来了。可以另外写一个isSolution函数来进行判断是否可行解。有时候还需要构建一个数据结构,把符合要求的解存起来,便于当得到所有解后,把解空间输出来。这个数据结构必须是全局的,可以作为参数之一传递给递归函数,也可以是成员变量。

概念及原理

这类问题的解可表示成一个n元组(x0,x1,…,xn-1),求满足约束条件的可行解,或进一步求使目标函数取最大(或最小)值的最优解问题,这类问题一般都可以用回溯法求解。
回溯法通过使用约束函数和限界函数来压缩需要实际生成的状态空间树的结点数,从而大大节省问题求解时间。

  • 子集数(Subset Trees):当所给问题是从n个元素的集合中找出满足某种性质的子集时,相应的解空间树称为子集树。
  • 排列树(Permutation Trees):当所给问题是确定n个元素满足某种性质的排列时,相应的解空间树称为排列树。

解空间树的三种节点

  • 活节点: 还有子节点未被搜索过的节点
  • 扩展节点: 当前正在尝试纵深方向搜索的节点
  • 死节点: 没有子节点或者所有子节点都被搜索过

确定了解空间的组织结构后,回溯法从根节点出发,以深度优先的方式搜索整个解空间。这个开始节点成为一个活节点,同时也成为当前的扩展节点。在当前的扩展节点处,搜索向纵深方向移至一个新节点。这个新节点就成为一个新的活节点,并成为当前扩展节点。如果在当前扩展节点处不能再向纵深方向移动,则当前的扩展节点就成为死节点。此时,应往回移动即回溯至最近的一个活节点处,并使这个活节点成为当前的扩展节点。回溯法即以这种方式递归地在解空间中搜索,直到找到所要求的解或者解空间中已无活节点为止。
以0/1背包问题为例

image

public class Knapsack {
    private int curWeight;

    private int curValue;

    private int bestValue;

    private final int CAPACTITY = 25;

    private final int NUM = 3;

    private int[] bestResult = new int[NUM];

    public void knapsack(int[] weights, int[] values) {
        //初始时从0开始搜索
        backtrack(weights, values, 0, new int[NUM]);
        for (int i = 0; i < NUM; i++) {
            System.out.println(bestResult[i]);
        }
        System.out.println(bestValue);
    }

    private void backtrack(int[] weights, int[] values, int index, int[] path) {
        if (index > NUM - 1) {//到达叶子节点,得到一个可行解
            if (curValue > bestValue) {//判断是否为最优解
                bestValue = curValue;//更新最优解
                for (int i = 0; i < NUM; i++) {
                    bestResult[i] = path[i];
                }
            }
            return;
        }
        //1,确定每一步的选择集,0/1背包问题每步的选择只有0和1
        for (int i = 0; i <= 1; i++) {
            //2,更新临时路径
            path[index] = i;
            //3,如果选择0,则直接向前扩展
            //4,如果选择1,并且没有超过容量,则可以继续扩展,否则剪枝
            if (curWeight + weights[index] * i <= CAPACTITY) {
                //4.1 更新当前值(做选择)
                curValue += values[index] * i;
                curWeight += weights[index] * i;
                //4.2 纵深扩展
                backtrack(weights, values, index + 1, path);
                //4.3 恢复当前值(撤销选择),以便回溯
                curValue -= values[index] * i;
                curWeight -= weights[index] * i;
            }
        }
    }
}

通用解法

一般用递归实现,递归函数设计:
1、必须要有一个临时变量(初始时可以就直接传递一个字面量或者常量进去)传递不完整的解,表示截至当前解的情况,因为每一步选择后,暂时还没构成完整的解,这个时候这个选择的不完整解,也要想办法传递给递归函数。也就是,把每次递归的不同情况传递给递归调用的函数。【每一步的解的汇总信息传递下去】表示临时路径。
2、可以有一个全局变量,用来存储完整的每个解,一般是个集合容器(也不一定要有这样一个变量,因为每次符合结束条件,不完整解就是完整解了,直接打印即可)。【存储完整的解空间,也可以用类的属性】
3、最重要的一点,一定要在参数设计中,可以得到结束条件。一个选择是可以传递一个递增变量,也许是数组的长度,也许是数量,索引等等。【结束条件】
4、要保证递归函数返回后,状态可以恢复到递归前,以此达到真正回溯。【恢复状态:下一次递归前,把当前这一步的选择清除或者还原】
回溯的意思就是要回去,递归函数自动保证了回去,但是我们设置的其他变量如果有必要的话也必须要回到原位。

通过递增变量或者临时路径进行扩展,看情况,一般递增变量扩展时增加1,临时路径扩展时尾部增加一步。路径代表已做过的选择,可以是索引值index,也可以是链表。
做选择、扩展递归下一步、撤销选择。

伪代码:

void findSolutions(t, other params) :
    //1,结束条件,一轮搜索结束,得到一个可行解
    if (t > n) :
        displaySolution();
        return;
    for (val = first to last) : //2,做选择
        if (isValid(val, n)) : //3,剪枝
            applyValue(val, n); //4,应用选择
            findSolutions(n+1, other params); //5,向前纵向扩展
            removeValue(val, n); //6,撤销选择

leetcode回溯算法题解

leetcode例题

416.分割等和子集
转化为[0/1背包问题]:

class Solution {
   public boolean canPartition(int[] nums) {
        if (nums.length <= 1) {
            return false;
        }
        int sum = 0;
        for (int element : nums) {
            sum += element;
        }
        if (sum % 2 != 0) {
            return false;
        }
        Arrays.sort(nums);
        return backtrack(nums.length - 1, sum / 2, nums);
    }

    public boolean backtrack(int index, int remainSum, int[] nums) {
        if (index <0 || nums[index] > remainSum) {
            return false;
        }
        if (nums[index] == remainSum) {
            return true;
        }

        for (int i = 1; i >= 0; i--) {//i++会超时
            remainSum -= nums[index] * i;
            if (backtrack(index - 1, remainSum, nums)) {
                return true;
            }
            remainSum += nums[index] * i;
        }
        return false;
    }
}

为了套用模板,写的不够简洁,有更简洁的写法。

254因子的组合
与前一题的不同之处在于,单个解向量的元素个数是不确定的。

class Solution {
   private List<List<Integer>> results = new ArrayList<>();

    public List<List<Integer>> getFactors(int n) {
        if (n <= 3) {
            return results;
        }
        LinkedList<Integer> path = new LinkedList<>();
        path.add(1);
        backtrack(n, path);
        return results;
    }

    private void backtrack(int remain, LinkedList<Integer> path) {
        if (remain == 1) {
            List<Integer> result = new LinkedList<>();
            for (int ele : path) {
                if (ele != 1) {
                    result.add(ele);
                }
            }
            Collections.sort(result);
            if (!results.contains(result) && result.size() != 1) {
                results.add(result);
            }
            return;
        }
        for (int i = 2; i <= remain; i++) {
            if (remain % i != 0) {
                continue;
            }
            path.add(i);
            remain = remain / i;
            backtrack(remain, path);
            path.removeLast();
            remain = remain * i;
        }
    }
}

51. N皇后问题

public class NQueens {
    private List<List<String>> res = new LinkedList<>();

    public List<List<String>> solveNQueens(int n) {
        char[][] board = new char[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(board[i], '.');
        }
        backtrack(0, board);
        return res;
    }

    /**
     * backtrack为标准的回溯法模板
     *
     * @param index 索引,或者已做选择的路径
     * @param board
     */
    private void backtrack(int index, char[][] board) {
        //结束条件为所有的皇后都已放置
        if (index == board.length) {
            res.add(chars2StrList(board));//把可行解加入到结果集
            return;
        }
        int cols = board[0].length;
        //选择列表为每一列
        for (int i = 0; i < cols; i++) {
            if (!isValid(board, index, i)) {//剪枝
                continue;
            }
            //做选择,在当前位置放置皇后
            board[index][i] = 'Q';
            //向纵深方向扩展一步
            backtrack(index + 1, board);
            //撤销选择
            board[index][i] = '.';
        }
    }

    private List<String> chars2StrList(char[][] board) {
        List<String> strList = new LinkedList<>();
        for (char[] row : board) {
            strList.add(String.valueOf(row));
        }
        return strList;
    }

    private boolean isValid(char[][] board, int row, int col) {
        //检查同一列有没有放置皇后
        for (int i = 0; i < row; i++) {
            if (board[i][col] == 'Q') {
                return false;
            }
        }
        //检查左上角的对角线有没有放置皇后
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }
        //检查右上角的对角线有没有放置皇后
        for (int i = row - 1, j = col + 1; i >= 0 && j < board.length; i--, j++) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }
}

1087.字母切换

class Solution {
    public String[] expand(String S) {
        if (!S.contains("{")) {
            return new String[] {S};
        }
        String s = S.replaceAll("\\{", " ").replaceAll("}", " ").replaceAll(",", "");
        String[] strs = s.split(" ");
        List<String> list = new ArrayList<>();
        for (int i = 0; i < strs.length; i++) {
            if (strs[i].length() != 0) {//"" length is 0
                list.add(strs[i]);
            }
        }

        List<String> listresult = new ArrayList<>();
        LinkedList<Character> path = new LinkedList<>();
        backtraceDfs(list, 0, path, listresult);

        Collections.sort(listresult);
        return listresult.toArray(new String[listresult.size()]);
    }

    void backtraceDfs(List<String> list, int index, LinkedList<Character> path, List<String> listresult) {

        if (index == list.size()) {
            StringBuilder builder = new StringBuilder();
            for (int k = 0; k < path.size(); k++) {
                builder.append(path.get(k));
            }
            listresult.add(builder.toString());

            return;
        }

        for (int j = 0; j < list.get(index).length(); j++) {
            path.add(list.get(index).charAt(j));
            backtraceDfs(list, index + 1, path, listresult);
            path.removeLast();
        }
    }
}

267.回文排列II

class Solution {
   private List<String> result = new ArrayList<>();
   
   public List<String> generatePalindromes(String s) {

        if (s.length() < 1) {
            return new ArrayList<String>();
        }
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            Character key = s.charAt(i);
            map.put(key, map.getOrDefault(key, 0) + 1);
        }
        Character ch = null;
        int size = 0;
        int count = 0;
        for (Character c : map.keySet()) {
            if (map.get(c) % 2 == 1) {
                map.put(c, map.get(c) - 1);
                ch = c;
                count++;
            }
            size += map.get(c) / 2;
        }
        if (count > 1) {
            return new ArrayList<String>();
        }
        char[] chars = new char[size];
        int i = 0;
        for (char c : map.keySet()) {
            for (int j = 0; j < map.get(c) / 2; j++) {
                chars[i++] = c;
            }
        }
        palindrome2(chars, new StringBuilder(), ch, new boolean[size]);
        return new ArrayList<>(result);
    }

    private void palindrome2(char[] chars, StringBuilder sb, Character ch, boolean[] visited) {
        if (sb.length() == chars.length) {
            StringBuilder temp = new StringBuilder(sb);
            StringBuilder reverse = new StringBuilder(sb).reverse();
            result.add(ch == null ? temp.append(reverse).toString() : temp.append(ch).append(reverse).toString());
            return;
        }
        for (int i = 0; i < chars.length; i++) {
            if (visited[i]) {
                continue;
            }
            if (i > 0 && !visited[i - 1] && chars[i] == chars[i - 1]) {
                continue;
            }
            sb.append(chars[i]);
            visited[i] = true;
            palindrome2(chars, sb, ch, visited);
            sb.deleteCharAt(sb.length() - 1);
            visited[i] = false;
        }
    }
   
}

总结

回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,定义解空间树,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

贪心法和动态规划法都要求问题最优解具有最优子结构特性。贪心法求解还要求设计最优量度标准,但这并非易事,这时候可以用回溯。回溯法是比贪心法和动态规划法更一般的方法。

回溯法

年份 事件 相关论文
1960 R. J. Walker第一次尝试全面阐述回溯编程的范围和方法 R. J. Walker(1960), An enumerative technique for a class of combinatorial problems.
1965 S. Golamb 和 L. Baumert.的方案进行修改提出.Backtrack programming Golomb, S. W., & Baumert, L. D. (1965). Backtrack programming. Journal of the ACM (JACM), 12(4), 516-524.
1976 Stallman, R. M., & Sussman, G. J. 提出相关性回溯法 Stallman, R. M., & Sussman, G. J. (1976). Forward reasoning and dependency-directed backtracking in a system for computer-aided circuit analysis.
1993 动态回溯法被提出 Ginsberg, M. L. (1993). Dynamic backtracking. journal of artificial intelligence research, 1, 25-46.

课后练习

37数独
1079活字印刷

智能网络论文

2019年智能网络调度的几篇论文:

  1. Zirui Zhuang, Jingyu Wang*, Qi Qi, Haifeng Sun, Jianxin Liao, Towards Greater Intelligence in Route Planning: A Graph-Aware Deep Learning Approach, IEEE System Journal, 2019 online. 路由规划
  2. Xiaoyuan Fu, F. Richard Yu, Jingyu Wang*, Qi Qi, Jianxin Liao, Deep Reinforcement Learning (DRL)-based Service Function Chain Embedding for NFV-Enabled IoT, IEEE Communication Magazine, 2019 online. 业务功能链嵌入
  3. Xiaoyuan Fu, F. Richard Yu, Jingyu Wang*, Qi Qi, Jianxin Liao, Dynamic Service Function Chain Embedding for NFV-Enabled IoT: A Deep Reinforcement Learning Approach, IEEE Transactions on Wireless Communications, 2019 online. 资源编排
  4. Jingyu Wang*, Bo He, Jing Wang, Tonghong Li, Intelligent VNFs Selection based on Traffic Identification in Vehicular Cloud Networks, IEEE Transactions on Vehicular Technology, 68(5) May 2019, pp. 4140 – 4147. 功能部署
  5. Qi Qi, Jingyu Wang, Zhanyu Ma, Haifeng Sun, Yufei Cao, Lingxin Zhang, Jianxin Liao, Knowledge-Driven Service Offloading Decision for Vehicular Edge Computing: A Deep Reinforcement Learning Approach. IEEE Transactions on Vehicular Technology 68(5): 4192-4203, 2019. 边缘卸载
  6. Jingyu Wang*, Zirui Zhuang, Qi Qi, Tonghong Li, Jianxin Liao, Deep reinforcement learning-based cooperative interactions among heterogeneous vehicular networks. Appl. Soft Comput. 82 (2019). 协作交互
  7. Jingyu Wang*, Yuhan Jing, Qi Qi, Tongtong Feng, Jianxin Liao, ALSR: An adaptive label screening and relearning approach for interval-oriented anomaly detection. Expert Syst. Appl. 136: 94-104 (2019) . 异常检测
  8. Haifeng Sun, Yunming Xiao, Jing Wang, Jingyu Wang, Qi Qi, Jianxin Liao, Xiulei Liu, Common Knowledge Based and One-Shot Learning Enabled Multi-Task Traffic Classification. IEEE Access 7: 39485-39495 (2019) 流量分类
  9. Jingyu Wang*, Zirui Zhuang, Qi Qi, Tonghong Li, Jianxin Liao, Deep reinforcement learning-based cooperative interactions among heterogeneous vehicular networks. Appl. Soft Comput. 82 (2019). 策略冲突博弈

还有早些年几篇老古董文章,和传输协议相关:
1、Jingyu Wang, Jianxin Liao, Tonghong Li, Jing Wang: On the collaborations of multiple selfish overlays using multi-path resources. Peer-to-Peer Networking and Applications 8(2): 203-215 (2015) 对等网多路径
2、Jingyu Wang, Jianxin Liao, Tonghong Li: OSIA: Out-of-order Scheduling for In-order Arriving in concurrent multi-path transfer. J. Network and Computer Applications 35(2): 633-643 (2012) 解决乱序问题
3、Jianxin Liao, Jinzhu Wang, Tonghong Li, Jing Wang, Jingyu Wang, Xiaomin Zhu: A distributed end-to-end overload control mechanism for networks of SIP servers. Computer Networks 56(12): 2847-2868 (2012) SIP流量控制
4、Jianxin Liao, Jingyu Wang, Tonghong Li, Xiaomin Zhu: Introducing multipath selection for concurrent multipath transfer in the future internet. Computer Networks 55(4): 1024-1035 (2011) 多路径选择
5、Jingyu Wang, Jianxin Liao, Xiaomin Zhu: Latent Handover: A flow-oriented progressive handover mechanism. Computer Communications 31(10): 2319-2340 (2008) 多路径切换
6、Jianxin Liao, Jingyu Wang, Xiaomin Zhu: A multi-path mechanism for reliable VoIP transmission over wireless networks. Computer Networks 52(13): 2450-2460 (2008) 多路径协议

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.