【Lintcode】815. Course Schedule IV

题目地址:

https://www.lintcode.com/problem/course-schedule-iv/description

给定一个 n n n个顶点的简单有向图,求一共有多少个不同的拓扑排序。

思路是DFS。枚举其所有可能的拓扑排序然后计数即可。具体来讲就是,先建图,并且记录每个顶点的入度。接着开始DFS,在每一个递归层,都去枚举该层可以选哪个顶点。显然能选择的顶点必须满足两个条件:第一,之前未选过;第二,入度为 0 0 0;每次选择好了顶点后,在进入下一层递归之前,需要将其出边删掉(也就是将其邻接点的入度减去 1 1 1),然后标记其为选择过;递归返回之前记得恢复现场。代码如下:

public class Solution {
    
    // 存拓扑序的计数
    private int res;
    
    /**
     * @param n: an integer, denote the number of courses
     * @param p: a list of prerequisite pairs
     * @return: return an integer,denote the number of topologicalsort
     */
    public int topologicalSortNumber(int n, int[][] p) {
        // Write your code here
        // 用邻接矩阵建图并且记录每个顶点的入度
        boolean[][] graph = new boolean[n][n];
        int[] indegrees = new int[n];
        for (int[] edge : p) {
            graph[edge[1]][edge[0]] = true;
            indegrees[edge[0]]++;
        }
        
        // 从第0层开始遍历
        dfs(0, graph, indegrees, new boolean[n], n);
        return res;
    }
    
    // count记录已经选择了多少个顶点
    private void dfs(int count, boolean[][] graph, int[] indegrees, boolean[] visited, int n) {
    	// 如果已经选择了n个顶点,说明找到了一个拓扑序,计数加一
        if (count == n) {
            res++;
            return;
        }
        
        // 接下来枚举当前位置可以放哪个顶点
        for (int i = 0; i < n; i++) {
        	// 如果之前未选过,并且其入度为0,则说明该顶点可以选
            if (!visited[i] && indegrees[i] == 0) {
            	// 标记其为选过,并将其出边全删掉
                visited[i] = true;
                for (int j = 0; j < n; j++) {
                    if (graph[i][j]) {
                        indegrees[j]--;
                    }
                }
                
                // 进入下一层递归
                dfs(count + 1, graph, indegrees, visited, n);
                
                // 恢复现场
                for (int j = 0; j < n; j++) {
                    if (graph[i][j]) {
                        indegrees[j]++;
                    }
                }
                visited[i] = false;
            }
        }
    }
}

时间复杂度由于有剪枝所以很难估计。空间复杂度 O ( V 2 ) O(V^2) O(V2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值