SDUT 判断给定图是否存在合法拓扑序列

题目描述

Problem Description

给定一个有向图,判断该有向图是否存在一个合法的拓扑序列。
Input

输入包含多组,每组格式如下。
第一行包含两个整数n,m,分别代表该有向图的顶点数和边数。(n<=10)
后面m行每行两个整数a b,表示从a到b有一条有向边。

Output

若给定有向图存在合法拓扑序列,则输出YES;否则输出NO。

Sample Input

1 0
2 2
1 2
2 1
Sample Output

YES
NO

分析 & 代码

拓扑排序问题思路就是找到一个入度为0的点a,然后把以这个点为起点的点的入度都减少一 ,然后判断这个时候是否又出现了入度为0的点,反复这个过程,知道没有入度为0的点结束如果所有的点此时入度都是0那么这个图中就有至少一条合法的拓扑路径否则就没有。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<memory.h>
#include<queue>
using namespace std;
int n,m;
int indegree[15];         //保存入度为0的点
int vis;                  //计数
vector<int> g[15];         //邻接表的方式储存边信息

int topo(){
    queue<int> sav;
    for(int i=1; i<=n; i++){
        if(indegree[i]==0)
            sav.push(i);
    }                             //第一次将入度为0的点加入队列    这个地方队列只是保存一下 像链表等结构都可以
    while(!sav.empty()){
        int temp = sav.front();
        sav.pop();                   //取出一个入度为0的点 然后把以这个点为起始点的边删掉  (a,b)其实就是b的indegree减一
        int len = g[temp].size();
        vis++;
        for(int i=0; i<len; i++){
            indegree[g[temp][i]]--;     //temp 也就是此时入度为0的点  以这个点开头的点入度都减一
            if(indegree[g[temp][i]]==0){     //判断一下是否又产生了新的入度为0的点 有的话加入进去
                sav.push(g[temp][i]);
            }
        }
    }
}
int main(){
    int a,b;
    while(cin>>n>>m){

        vis = 0;
        memset(indegree, 0, sizeof(indegree));
        for(int i=0; i<15; i++){
            g[i].clear();
        }                                          //日常初始化

        for(int i=0; i<m; i++){
            cin>>a>>b;
            indegree[b]++;                   //边输入 边统计入度
            g[a].push_back(b);
        }
        topo();
        if(vis==n)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
上升子序列是指在一个序列中,如果一些数字呈上升趋势排列,那么这些数字就可以组成一个上升子序列。比如序列 {1, 3, 5, 2, 4, 6} 中,{1, 3, 5} 和 {2, 4, 6} 就是两个上升子序列。 SDUT(Shandong University of Technology,山东理工大学)的上升子序列问题是这样的:给定一个长度为 n 的序列,出其中的一个最长的上升子序列。例如,对于序列 {1, 4, 3, 5, 6, 2},其最长的上升子序列为 {1, 4, 5, 6},长度为 4。 求解这个问题可以使用动态规划算法。我们可以定义一个数组 dp,其中 dp[i] 表示以第 i 个数字为结尾的最长上升子序列的长度。初始时,dp[i] 的值都为 1,因为每个数字本身就可以组成一个长度为 1 的上升子序列。然后,我们从第 2 个数字开始依次计算 dp[i] 的值,计算方法如下: - 对于第 i 个数字,我们枚举它前面的所有数字 j,如果 j 小于 i,那么 dp[i] 的值可以更新为 dp[j]+1(因为以 j 为结尾的最长上升子序列再加上数字 i 就可以得到以 i 为结尾的最长上升子序列)。 - 在枚举 j 的过程中,我们还需要维护一个变量 max_len,它表示所有 dp[j]+1 的最大值。这是因为以 i 为结尾的最长上升子序列并不一定是以 j 为结尾的最长上升子序列再加上一个数字 i 得到的,有可能是以 j 为结尾的最长上升子序列和以 i 为结尾的最长上升子序列中的某个更长的子序列拼接得到的。 - 最终,我们遍历整个 dp 数组,出其中的最大值即可。 下面是 Python 代码实现: ```python def longest_increasing_subsequence(nums): n = len(nums) dp = [1] * n max_len = 1 for i in range(1, n): for j in range(i): if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j]+1) max_len = max(max_len, dp[i]) return max_len ``` 时间复杂度为 O(n^2)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值