Day_39关键路径

news2024/11/23 20:25:27

目录

一. 关于关键路径

        1. 有向无环图

        2. AOV网

        3. 拓补排序

         4. 关键路径

二. 如何实现寻找关键路径

三. 关键路径的代码实现

        1. 正向计算

        1.1 计算每个节点的入度

        1.2 拓扑排序(计算每个节点最早开始的时间)

        2. 反向计算

        2.1 计算每个节点的出度,计算方法类似1.1,这里不再赘述。

        2.2 逆拓扑排序(计算每个节点最晚开始的时间)

        3. 计算关键路径

四. 代码展示

五. 数据测试

六. 总结与反思


一. 关于关键路径

        1. 有向无环图

        若一个有向图中不存在环,则称为有向无环图,简称DAG图。

        2. AOV网

        若用DAG图表示一个工程,其顶点表示活动,用有向边<V_{i},V_{j}> 表示活动V_{i}必须先于活动V_{j}进行的这样一种关系,则将这种有向图称为顶点表示活动的网格,记为AOV网。在AOV网中,活动V_{i}是活动V_{j}的直接前驱,活动V_{j}是活动V_{i}的直接后继,这种前驱关系和后继关系具有传递性,且任何活动V_{i}不能以它自己作为自己的前驱或后继。

        3. 拓补排序

        在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序。

        ①每个顶点出现且只出现一次。

       ②若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径,或定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。

        对一个AOV网进行拓扑排序的算法有很多,下面介绍比较常用的一种方法的步骤:

        从AOV网中选择一个没有前驱的顶点输出;从网中删除该顶点和所有以它为起点的有向边;重复前面上述两步直到当前的AOV网为空或当前网中不存在无前驱的顶点为止。

        图G1-G6为拓扑排序过程的示例

        第一步找到节点1的入度为0,输出1,并且删除与节点1直接相连的有向边

        第二步找到节点2的入度为0,输出2,并且删除与节点2直接相连的有向边

        第三步找到节点3的入度为0,输出3,并且删除与节点3直接相连的有向边

        第四步找到节点4的入度为0,输出4,并且删除与节点4直接相连的有向边

        第五步找到节点5的入度为0,输出5。

图G1
图G2
图G3

图G4
图G5
图G6

         4. 关键路径

        在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为用边表示活动的网络,简称AOE网。AOE网和AOV网都是有向无环图,不同之处在于它们的边和顶点所代表的含义是不同的,AOE网中的边有权值;而AOV网中的边无权值,仅表示顶点之间的前后关系。

         AOE网具有以下两个性质:
        ①只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始;
        ②只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。

         在AOE网中仅有一个入度为0的顶点,称为开始顶点(源点),它表示整个工程的开始;网中也仅存在一个出度为0的顶点,称为结束顶点(汇点),它表示整个工程的结束。在AOE网中,有些活动是可以并行进行的。从源点到汇点的有向路径可能有多条,并且这些路径长度可能不同。完成不同路径上的活动所需的时间虽然不同,但是只有所有路径上的活动都已完成,整个工程才能算结束。因此,从源点到汇点的所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动。

         完成整个工程的最短时间就是关键路径的长度,即关键路径上各活动花费开销的总和。这是因为关键活动影响了整个工程的时间,即若关键活动不能按时完成,则整个工程的完成时间就会延长。因此,只要找到了关键活动,就找到了关键路径,也就可以得出最短完成时间。

二. 如何实现寻找关键路径

        现解释符号:事件V_{k}的最早发生时间V_{ek},事件V_{k}的最晚发生时间V_{lk}

        求关键路径的算法步骤如下:

        step1:从源点出发,令V_{eStart}=0,按拓扑有序求其余顶点的最早发生时间V_{ek}

        step2:从汇点出发,令V_{lLast}=V_{eLast},按拓扑有序求其预定点的最迟发生时间V_{lk}

        step3:根据各顶点的V_{ek}V_{lk}的差值为0,计算出关键路径的节点,即这些顶点构成关键路径。

三. 关键路径的代码实现

        1. 正向计算

        1.1 计算每个节点的入度

        根据第i行邻接矩阵不为-1的列的个数,计算第i个节点的入度,得到的结果存储在矩阵tempInDegrees里面。

        // Step 1. The in-degree of each node.
        int[] tempInDegrees = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(i, j) != -1) {
                    tempInDegrees[j]++;
                } // Of if
            } // Of for j
        } // Of for i
        System.out.println("In-degree of nodes: " + Arrays.toString(tempInDegrees));

        1.2 拓扑排序(计算每个节点最早开始的时间)

        首先初始化设置每一个节点最早开始的时间都为0,用矩阵tempEarliestTimeArray记录。接着从节点0开始循环,找到入度为0的节点j,移出节点j,更新图中剩余节点的信息:若邻接矩阵第0行的第j列不为-1(0号节点与j号节点连通),计算tempValue= 0号节点最早开始时间tempEarliestTimeArray[0] +节点0到节点j的时间;若tempValue计算得到的结果大于tempEarliestTimeArray[j](j号节点最早能多久开始),那么更新tempEarliestTimeArray[j]=tempValue(保证节点j最早能够开始的时间一定是路径里面最大的,否则就是节点j在条件没有满足的情况下开始(不符合题意)),将j号节点的入度tempInDegrees[j]减1;继续找入度为0的节点i,按照上述计算;当0号节点循环完成(第一个入度为0)。接着寻找第二个入度为0的节点k按照0号节点一样对计算方法,得到计算结果...最终我们得到所有节点最早开始的矩阵tempEarliestTimeArray。

        // Step 2. Topology sorting.
        int[] tempEarliestTimeArray = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            // This node cannot be removed.
            if (tempInDegrees[i] > 0) {
                continue;
            } // Of if

            System.out.println("Removing " + i);

            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(i, j) != -1) {
                    tempValue = tempEarliestTimeArray[i] + weightMatrix.getValue(i, j);
                    if (tempEarliestTimeArray[j] < tempValue) {
                        tempEarliestTimeArray[j] = tempValue;
                    } // Of if
                    tempInDegrees[j]--;
                } // Of if
            } // Of for j
        } // Of for i

        System.out.println("Earlest start time: " + Arrays.toString(tempEarliestTimeArray));

        2. 反向计算

        2.1 计算每个节点的出度,计算方法类似1.1,这里不再赘述。

        // Step 3. The out-degree of each node.
        int[] tempOutDegrees = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(i, j) != -1) {
                    tempOutDegrees[i]++;
                } // Of if
            } // Of for j
        } // Of for i
        System.out.println("Out-degree of nodes: " + Arrays.toString(tempOutDegrees));

        2.2 逆拓扑排序(计算每个节点最晚开始的时间)

        用矩阵tempLatestTimeArray记录每个节点最晚开始的时间,初始化tempLatestTimeArray都等于tempEarliestTimeArray[5]。同样的道理我们寻找出度为0的节点,第一个出度为0的节点是5。寻找节点j直接与节点5相连,若tempValue=tempLatestTimeArray[i](节点i最迟开始时间)-节点j到节点i的时间小于tempLatestTimeArray[j](节点j的最迟开始时间),那么更新tempLatestTimeArray[j]=tempValue。节点j的出度tempOutDegrees[j]减1。继续循环直到邻接矩阵第6行结束。最后继续寻找下一个出度为0的节点i,继续上述循环。

        // Step 4. Reverse topology sorting.
        int[] tempLatestTimeArray = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            tempLatestTimeArray[i] = tempEarliestTimeArray[numNodes - 1];
        } // Of for i

        for (int i = numNodes - 1; i >= 0; i--) {
            // This node cannot be removed.
            if (tempOutDegrees[i] > 0) {
                continue;
            } // Of if

            System.out.println("Removing " + i);

            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(j, i) != -1) {
                    tempValue = tempLatestTimeArray[i] - weightMatrix.getValue(j, i);
                    if (tempLatestTimeArray[j] > tempValue) {
                        tempLatestTimeArray[j] = tempValue;
                    } // Of if
                    tempOutDegrees[j]--;
                    System.out.println("The out-degree of " + j + " decreases by 1.");
                } // Of if
            } // Of for j
        } // Of for i

        System.out.println("Latest start time: " + Arrays.toString(tempLatestTimeArray));

        3. 计算关键路径

        我们得到了两个矩阵tempEarliestTimeArray,tempLatestTimeArray,将这两个矩阵相减,得到值为0的节点,那么就是关键路径上面的节点,得到最终答案。

        boolean[] resultCriticalArray = new boolean[numNodes];
        for (int i = 0; i < numNodes; i++) {
            if (tempEarliestTimeArray[i] == tempLatestTimeArray[i]) {
                resultCriticalArray[i] = true;
            } // Of if
        } // Of for i

        System.out.println("Critical array: " + Arrays.toString(resultCriticalArray));
        System.out.print("Critical nodes: ");
        for (int i = 0; i < numNodes; i++) {
            if (resultCriticalArray[i]) {
                System.out.print(" " + i);
            } // Of if
        } // Of for i

四. 代码展示

        主类:

package Day_39;
import Day_38.Net;
public class demo1 {
    /**
     *********************
     * The entrance of the program.
     *
     * @param args
     *            Not used now.
     *********************
     */
    public static void main(String args[]) {
        int MAX_DISTANCE= 1000;
//        Net tempNet0 = new Net(3);
//        System.out.println(tempNet0);
//
//        int[][] tempMatrix1 = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };
//        Net tempNet1 = new Net(tempMatrix1);
//        System.out.println(tempNet1);
//
//        // Dijkstra
        tempNet1.dijkstra(1);
//
//        // An undirected net is required.
//        int[][] tempMatrix2 = { { 0, 7, MAX_DISTANCE, 5, MAX_DISTANCE }, { 7, 0, 8, 9, 7 },
//                { MAX_DISTANCE, 8, 0, MAX_DISTANCE, 5 }, { 5, 9, MAX_DISTANCE, 0, 15, },
//                { MAX_DISTANCE, 7, 5, 15, 0 } };
//        Net tempNet2 = new Net(tempMatrix2);
//        tempNet2.prim();

        // A directed net without loop is required.
        // Node cannot reach itself. It is indicated by -1.
        int[][] tempMatrix3 = { { -1, 3, 2, -1, -1, -1 }, { -1, -1, -1, 2, 3, -1 },
                { -1, -1, -1, 4, -1, 3 }, { -1, -1, -1, -1, -1, 2 }, { -1, -1, -1, -1, -1, 1 },
                { -1, -1, -1, -1, -1, -1 } };

        Net tempNet3 = new Net(tempMatrix3);
        System.out.println("-------critical path");
        tempNet3.criticalPath();
    }// Of main

}

        调用类:

package Day_38;

import Day_31.IntMatrix;

import java.util.Arrays;

/**
 * Weighted graphs are called nets.
 *
 * @author An Jian 2569222191@qq.com.
 */
public class Net {

    /**
     * The maximal distance. Do not use Integer.MAX_VALUE.
     */
    public static final int MAX_DISTANCE = 10000;

    /**
     * The number of nodes.
     */
    int numNodes;

    /**
     * The weight matrix. We use int to represent weight for simplicity.
     */
    IntMatrix weightMatrix;

    /**
     * ********************
     * The first constructor.
     *
     * @param paraNumNodes The number of nodes in the graph.
     *                     ********************
     */
    public Net(int paraNumNodes) {
        numNodes = paraNumNodes;
        weightMatrix = new IntMatrix(numNodes, numNodes);
        for (int i = 0; i < numNodes; i++) {
            // For better readability, you may need to write fill() in class
            // IntMatrix.
            Arrays.fill(weightMatrix.getData()[i], MAX_DISTANCE);
        } // Of for i
    }// Of the first constructor

    /**
     * ********************
     * The second constructor.
     *
     * @param paraMatrix The data matrix.
     *                   ********************
     */
    public Net(int[][] paraMatrix) {
        weightMatrix = new IntMatrix(paraMatrix);
        numNodes = weightMatrix.getRows();
    }// Of the second constructor

    /**
     * ********************
     * Overrides the method claimed in Object, the superclass of any class.
     * ********************
     */
    public String toString() {
        String resultString = "This is the weight matrix of the graph.\r\n" + weightMatrix;
        return resultString;
    }// Of toString

    /**
     * ********************
     * The Dijkstra algorithm: shortest path from the source to all nodes.
     *
     * @param paraSource The source node.
     * @return The distances to all nodes.
     * ********************
     */
    public int[] dijkstra(int paraSource) {
        // Step 1. Initialize.
        int[] tempDistanceArray = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            tempDistanceArray[i] = weightMatrix.getValue(paraSource, i);
        } // Of for i

        int[] tempParentArray = new int[numNodes];
        Arrays.fill(tempParentArray, paraSource);
        // -1 for no parent.
        tempParentArray[paraSource] = -1;

        // Visited nodes will not be considered further.
        boolean[] tempVisitedArray = new boolean[numNodes];
        tempVisitedArray[paraSource] = true;

        // Step 2. Main loops.
        int tempMinDistance;
        int tempBestNode = -1;
        for (int i = 0; i < numNodes - 1; i++) {
            // Step 2.1 Find out the best next node.
            tempMinDistance = Integer.MAX_VALUE;
            for (int j = 0; j < numNodes; j++) {
                // This node is visited.
                if (tempVisitedArray[j]) {
                    continue;
                } // Of if

                if (tempMinDistance > tempDistanceArray[j]) {
                    tempMinDistance = tempDistanceArray[j];
                    tempBestNode = j;
                } // Of if
            } // Of for j

            tempVisitedArray[tempBestNode] = true;

            // Step 2.2 Prepare for the next round.
            for (int j = 0; j < numNodes; j++) {
                // This node is visited.
                if (tempVisitedArray[j]) {
                    continue;
                } // Of if

                // This node cannot be reached.
                if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {
                    continue;
                } // Of if

                if (tempDistanceArray[j] > tempDistanceArray[tempBestNode]
                        + weightMatrix.getValue(tempBestNode, j)) {
                    // Change the distance.
                    tempDistanceArray[j] = tempDistanceArray[tempBestNode]
                            + weightMatrix.getValue(tempBestNode, j);
                    // Change the parent.
                    tempParentArray[j] = tempBestNode;
                } // Of if
            } // Of for j

            // For test
            System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));
            System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
        } // Of for i

        // Step 3. Output for debug.
        System.out.println("Finally");
        System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));
        System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
        return tempDistanceArray;
    }// Of dijkstra

    /**
     * ********************
     * The minimal spanning tree.
     *
     * @return The total cost of the tree.
     * ********************
     */
    public int prim() {
        // Step 1. Initialize.
        // Any node can be the source.
        int tempSource = 0;
        int[] tempDistanceArray = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            tempDistanceArray[i] = weightMatrix.getValue(tempSource, i);
        } // Of for i

        int[] tempParentArray = new int[numNodes];
        Arrays.fill(tempParentArray, tempSource);
        // -1 for no parent.
        tempParentArray[tempSource] = -1;

        // Visited nodes will not be considered further.
        boolean[] tempVisitedArray = new boolean[numNodes];
        tempVisitedArray[tempSource] = true;

        // Step 2. Main loops.
        int tempMinDistance;
        int tempBestNode = -1;
        for (int i = 0; i < numNodes - 1; i++) {
            // Step 2.1 Find out the best next node.
            tempMinDistance = Integer.MAX_VALUE;
            for (int j = 0; j < numNodes; j++) {
                // This node is visited.
                if (tempVisitedArray[j]) {
                    continue;
                } // Of if

                if (tempMinDistance > tempDistanceArray[j]) {
                    tempMinDistance = tempDistanceArray[j];
                    tempBestNode = j;
                } // Of if
            } // Of for j

            tempVisitedArray[tempBestNode] = true;

            // Step 2.2 Prepare for the next round.
            for (int j = 0; j < numNodes; j++) {
                // This node is visited.
                if (tempVisitedArray[j]) {
                    continue;
                } // Of if

                // This node cannot be reached.
                if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {
                    continue;
                } // Of if

                // Attention: the difference from the Dijkstra algorithm.
                if (tempDistanceArray[j] > weightMatrix.getValue(tempBestNode, j)) {
                    // Change the distance.
                    tempDistanceArray[j] = weightMatrix.getValue(tempBestNode, j);
                    // Change the parent.
                    tempParentArray[j] = tempBestNode;
                } // Of if
            } // Of for j

            // For test
            System.out.println(
                    "The selected distance for each node: " + Arrays.toString(tempDistanceArray));
            System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
        } // Of for i

        int resultCost = 0;
        for (int i = 0; i < numNodes; i++) {
            resultCost += tempDistanceArray[i];
        } // Of for i

        // Step 3. Output for debug.
        System.out.println("Finally");
        System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
        System.out.println("The total cost: " + resultCost);

        return resultCost;
    }// Of prim

    /**
     *********************
     * Critical path. Net validity checks such as loop check not implemented.
     * The source should be 0 and the destination should be n-1.
     *
     * @return The node sequence of the path.
     *********************
     */
    public boolean[] criticalPath() {
        // One more value to save simple computation.
        int tempValue;

        // Step 1. The in-degree of each node.
        int[] tempInDegrees = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(i, j) != -1) {
                    tempInDegrees[j]++;
                } // Of if
            } // Of for j
        } // Of for i
        System.out.println("In-degree of nodes: " + Arrays.toString(tempInDegrees));

        // Step 2. Topology sorting.
        int[] tempEarliestTimeArray = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            // This node cannot be removed.
            if (tempInDegrees[i] > 0) {
                continue;
            } // Of if

            System.out.println("Removing " + i);

            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(i, j) != -1) {
                    tempValue = tempEarliestTimeArray[i] + weightMatrix.getValue(i, j);
                    if (tempEarliestTimeArray[j] < tempValue) {
                        tempEarliestTimeArray[j] = tempValue;
                    } // Of if
                    tempInDegrees[j]--;
                } // Of if
            } // Of for j
        } // Of for i

        System.out.println("Earlest start time: " + Arrays.toString(tempEarliestTimeArray));

        // Step 3. The out-degree of each node.
        int[] tempOutDegrees = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(i, j) != -1) {
                    tempOutDegrees[i]++;
                } // Of if
            } // Of for j
        } // Of for i
        System.out.println("Out-degree of nodes: " + Arrays.toString(tempOutDegrees));

        // Step 4. Reverse topology sorting.
        int[] tempLatestTimeArray = new int[numNodes];
        for (int i = 0; i < numNodes; i++) {
            tempLatestTimeArray[i] = tempEarliestTimeArray[numNodes - 1];
        } // Of for i

        for (int i = numNodes - 1; i >= 0; i--) {
            // This node cannot be removed.
            if (tempOutDegrees[i] > 0) {
                continue;
            } // Of if

            System.out.println("Removing " + i);

            for (int j = 0; j < numNodes; j++) {
                if (weightMatrix.getValue(j, i) != -1) {
                    tempValue = tempLatestTimeArray[i] - weightMatrix.getValue(j, i);
                    if (tempLatestTimeArray[j] > tempValue) {
                        tempLatestTimeArray[j] = tempValue;
                    } // Of if
                    tempOutDegrees[j]--;
                    System.out.println("The out-degree of " + j + " decreases by 1.");
                } // Of if
            } // Of for j
        } // Of for i

        System.out.println("Latest start time: " + Arrays.toString(tempLatestTimeArray));

        boolean[] resultCriticalArray = new boolean[numNodes];
        for (int i = 0; i < numNodes; i++) {
            if (tempEarliestTimeArray[i] == tempLatestTimeArray[i]) {
                resultCriticalArray[i] = true;
            } // Of if
        } // Of for i

        System.out.println("Critical array: " + Arrays.toString(resultCriticalArray));
        System.out.print("Critical nodes: ");
        for (int i = 0; i < numNodes; i++) {
            if (resultCriticalArray[i]) {
                System.out.print(" " + i);
            } // Of if
        } // Of for i
        System.out.println();

        return resultCriticalArray;
    }// Of criticalPath

}// Of class Net

五. 数据测试

        此次代码内部数据对应的AOE图如图H1所示,对应的邻接矩阵如图H2所示

图H1
图H2

        代码运行的结果(部分): 

六. 总结与反思

        关键路径的代码难以理解的地方很多,这个需要我们把握名词的每一个定义,类似于什么是AOV网,AOE网?它们的区别是什么?什么是拓补排序?拓扑排序和关键路径的联系在哪里等等之类。除此之外我们还需要理解算法的逻辑思维过程,只有把握好这两个方面才有可能看的懂闵老师写的代码(这里不得不说闵老师的代码写的真的很清楚,我感觉理解的很快QAQ)。上述完成之后,意指算法部分完成,代码的话就是要根据算法的思维过程逢山开路,遇水架桥(像这一小节里面的出度,入度这里算法和代码其实是有一个转化过程的)需要什么补充什么,最后对于代码里面实在理解不到的地方,我的建议是用人脑模拟计算机运行一遍(这招非常有用,有时候我不知道这个变量是干什么的,当我自己模拟运行一次之后豁然开朗)。

        最后补充一句吧:路漫漫其修远兮,吾将上下而求索,加油吧少年!!!

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617760.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于jupyter的线性回归练习

文章目录 练习1&#xff1a;线性回归介绍1 实现简单示例函数1.1 提交解决方案 2 单变量线性回归2.1 绘制数据2.2 梯度下降2.2.1 更新公式2.2.2 实现2.2.3 计算成本J(θ)2.2.4 梯度下降 2.3 可视化成本函数 选做练习3 多变量线性回归3.1 特征标准化3.2 梯度下降 总结 练习1&…

第六章:多表查询

第六章&#xff1a;多表查询 ​ 多表查询&#xff0c;也称为关联查询&#xff0c;指两个或更多个表一起完成查询操作。 ​ 前提条件&#xff1a;这些一起查询的表之间是有关系的(一对一、一对多)&#xff0c;它们之间一定是有关联字段&#xff0c;这个关联字段可能建立了外键…

SciencePub学术 | 人工智能类重点SCIEI征稿中

SciencePub学术 刊源推荐: 人工智能类重点SCI&EI征稿中&#xff01;影响因子高&#xff0c;对国人友好。信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 人工智能类重点SCI&EI 【期刊简介】IF&#xff1a;7.5-8.0&#xff0c;JCR1区&#xff0…

chatgpt赋能python:Python如何获取图片的尺寸

Python如何获取图片的尺寸 如果你在使用Python编程&#xff0c;常常需要获取图片的尺寸&#xff0c;本文将介绍如何使用Python获取图片的尺寸&#xff0c;同时还会介绍一些常用的Python库用于图像处理。 PIL库 PIL&#xff08;Python Imaging Library&#xff09;是Python中…

chatgpt赋能python:Python中如何设置空格

Python中如何设置空格 作为一门流行的编程语言&#xff0c;Python被广泛地应用于各种领域。在编写Python代码时&#xff0c;空格的使用非常重要。适当的空格设置可以让代码易读易懂&#xff0c;同时也有助于提高代码的可维护性和可重用性。 什么是空格 在Python中&#xff0…

shell脚本:循环结束语句二

shell脚本-循环结束语句二 二、循环结束语句&#xff1a;1.break&#xff1a;跳出循环。2.continue&#xff1a;3.while&#xff1a;4.until&#xff1a;条件不成立时&#xff0c;跳出循环。5.总结&#xff1a; 三、操作演练&#xff1a; 二、循环结束语句&#xff1a; 1.brea…

QT CTK插件开发(六) 多对一插件

CTK在软件的开发过程中可以很好的降低复杂性、使用 CTK Plugin Framework 提供统一的框架来进行开发增加了复用性 将同一功能打包可以提供多个应用程序使用避免重复性工作、可以进行版本控制提供了良好的版本更新迭代需求、并且支持动态热拔插 动态更新、开发更加简单快捷 方便…

基于jupyter的逻辑回归练习

文章目录 练习2&#xff1a;逻辑回归介绍1 Logistic回归1.1 数据可视化1.2 实现1.2.1 Sigmoid函数1.2.2 代价函数和梯度1.2.2.1 代价函数1.2.2.2 梯度下降 1.2.3 寻找最优参数1.2.4 评估逻辑回归 2 正则化逻辑回归2.1 数据可视化2.2 特征映射2.3 代价函数和梯度 2.4 寻找最优参…

腾讯云618云服务器优惠活动价格表

2023年腾讯云618年中促销活动已经正式开始了&#xff0c;腾讯云多款云服务都有特惠&#xff0c;下面给大家分享腾讯云618云服务器优惠活动价格表&#xff0c;记得抓住这次上云好时机&#xff01; 目录 一、腾讯云618活动入口 二、轻量应用服务器优惠价格表 三、CVM云服务器优…

【连续介质力学】二阶张量的图像表示

二阶张量在特定方向的投影 法向和切向分量 二阶张量T投影到 n ^ \hat n n^方向的结果是 t ⃗ ( n ^ ) T ⋅ n ^ \vec t^{(\hat n)}T \cdot \hat n t (n^)T⋅n^&#xff0c;其中 t ⃗ ( n ^ ) \vec t^{(\hat n)} t (n^)可以分解成&#xff1a; t ⃗ ( n ^ ) T ⃗ N T ⃗ S…

指针(三)

文章内容 1. 字符指针 2. 数组指针 3. 指针数组 文章内容 1. 字符指针 指针的概念&#xff1a; 1. 指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2. 指针的大小是固定的4/8个字节&#xff08;32位平台/64位平台&#xff09;。 3. 指针…

适配器stack和queue

目录 什么是适配器 模拟实现stack stack的特性 STL中stack的基本框架 接口实现 模拟实现queue queue的特性 STL中queue的框架 什么是适配器 适配器&#xff1a;所谓适配&#xff0c;适配的是容器(vector,list,deque....) 也就是不管是什么容器&#xff0c;都可以套用适…

chatgpt赋能python:Python如何设置输入的SEO

Python如何设置输入的SEO Python是一种高级的编程语言&#xff0c;具有容易上手、可扩展和开源等特点&#xff0c;因此在软件开发过程中得到广泛的应用。然而&#xff0c;如果您想让您的Python项目在搜索引擎上获得更好的排名和流量&#xff0c;您需要考虑如何设置输入的SEO。…

二叉搜索树(Binary Seach Tree)模拟实现

目录 二叉搜索树的性质 二叉搜索树的实现 结点类 接口类(BSTree) 二叉搜索树的插入(insert) 二叉搜索树的查找(find) 二叉搜索树删除(erase) 第二种、删除的结点右子树为空 第三种、删除的结点左子树为空 第四种、删除的结点左右都不为空 实现 二叉搜索树模拟实现代…

基于jupyter的轮廓检测及功能

文章目录 一、实验介绍二、实验步骤三、实验任务任务一&#xff1a;轮廓特征练习一: 找到每个轮廓的方向任务二&#xff1a;边界矩形练习二: 围绕轮廓裁剪图像 总结 一、实验介绍 1. 实验内容 本实验将学习轮廓检测及功能。 2. 实验要点 生成二进制图像来查找轮廓找到并画出…

kotlin函数返回函数

kotlin函数返回函数 https://blog.csdn.net/zhangphil/category_12220817.htmlhttps://blog.csdn.net/zhangphil/category_12220817.html 例1&#xff1a; // func返回匿名函数 fun func(msg: String): (String, Int) -> String {println("func函数 msg:$msg")/…

电能管理系统多功能电力仪表的应用 安科瑞 许敏

摘 要&#xff1a;基于车间用电设备的电能管理系统架构思路及实施方法&#xff0c;从硬件和软件方面对此方法进行了阐述。对车间旧设备改造以及新的电能管理系统提供一种思路和便捷的方法。 关键词&#xff1a;电能管理系统&#xff1b;多功能电力仪表&#xff1b;PLC&#x…

Azure Log Analytics:与Power BI集成

注&#xff1a;本文最初发布于https://d-bi.gitee.io, 2023年6月迁移至CSDN 前述 Azure Log Analytics是Azure Monitor中的一项分析服务。本文将讲述通过Log Analytics与Power BI集成的方式&#xff0c;获取Power BI工作区内的日志信息&#xff0c;包括各PBI数据集的CPU消耗&a…

6/5~6/6总结

创建存储过程 DELIMITER // CREATE PROCEDURE usingid() BEGIN SELECT AVG(id) FROM user; END // DELIMITER ; 要用DELIMITER //指定结束符为 "//", 要调用该存储过程&#xff1a; CAll usingid; 创建成功后在navicat里面的函数界面可以看见刚刚创建的存储过程…

【TCP/IP】IP地址与域名之间的转换 - gethostbyname 和 gethostbyaddr函数

目录 域名系统 DNS服务器 IP地址和域名之间的转换 通过域名获取IP地址 通过IP地址获取域名 域名系统 域名系统&#xff08;英文&#xff1a;Domain Name System&#xff0c;缩写&#xff1a;DNS&#xff09;是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式…