拓扑相关题目

有关拓扑一个挺直观的图:

1.luogu P1347 排序

直通

思路:

  题目中明确的提到:确定n个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况。

  所以我们可以每读入一个条件,就进行一遍Floyd,判断顺序的条件就是:

    枚举i,然后用map数组记录一下比i要大的个数,如果n-sum==s+1(s+1的原因是因为我们是从0开始计数的),那么就用一个q数组记录下来

  而如果在给出的n之内,只要有一个没有被确定,我们就不能够说已经排好序了

  还有一点需要注意的是:

·    如果出现了map[i][i]=true的情况,则说明不合法,输出"Inconsistency found after x relations.",其中的x就是我们输入时所用到的i

坑点:

  别忘了输出".",这个炒鸡重要!

上代码:

#include <iostream>
#include <cstdio>
using namespace std;

const int E = 26;
const char a[E]={‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘,‘G‘,‘H‘,‘I‘,‘J‘,‘K‘,‘L‘,‘M‘,‘N‘,‘O‘,‘P‘,‘Q‘,‘R‘,‘S‘,‘T‘,‘U‘,‘V‘,‘W‘,‘X‘,‘Y‘,‘Z‘};
int n,m;
char b[5];
int q[E];
bool map[E][E];

int floyd() {
    for(int k=0; k<n; k++)
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(map[i][k] && map[k][j])
                    map[i][j]=true;
    for(int i=0; i<n; i++) if(map[i][i]) return 2; //不合法
    for(int s=0; s<n; s++) { //枚举顺序
        int sum,x=-1;
        for(int i=0; i<n; i++) {
            sum=0; //有几个比i要大的
            for(int j=0; j<n; j++) if(map[i][j]) sum++;
            if(n-sum==s+1) x=i; //匹配成功
        }
        if(x==-1) return 0; //该位没有被确定
        q[s]=x;
    }
    return 1;
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1,u,v; i<=m; i++) {
        scanf("%s",b);
        u=b[0]-‘A‘,v=b[2]-‘A‘;
        map[u][v]=true;
        int p=floyd();
        if(p==1) {
            printf("Sorted sequence determined after %d relations: ",i);
            for(int i=0; i<n; i++) printf("%c",a[q[i]]);printf(".");
            return 0;
        }
        else if(p==2) {
            printf("Inconsistency found after %d relations.",i);
            return 0;
        }
    }
    printf("Sorted sequence cannot be determined.");
    return 0;
}

2.luogu P1137 旅行计划

直通

思路:

  用拓扑序列+dp来做

  转移方程是 ans[v]=max(ans[v],ans[u]+1);(其中u的顺序为拓扑的顺序)

上代码:

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

const int N = 100001;
const int M = 200001;
int n,m,u,v;
int ans[N];

struct node {
    int next,to;
}e[M];
int top,head[N];
void add(int u,int v) {
    top++;
    e[top].to=v;
    e[top].next=head[u];
    head[u]=top;
}

queue<int>q;
int ru[N],c[M];
void topo() {
    top=0;
    for(int i=1; i<=n; i++)
        if(!ru[i])
            q.push(i);
    while(!q.empty()) {
        u=q.front();
        q.pop();
        c[++top]=u;
        for(int i=head[u]; i; i=e[i].next) {
            v=e[i].to;
            ru[v]--;
            if(!ru[v]) q.push(v);
        }
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&u,&v);
        add(u,v);
        ru[v]++;
    }
    topo();
    for(int i=1; i<=n; i++) ans[i]=1;
    for(int x=1; x<=n; x++) {
        u=c[x];
        for(int i=head[u]; i; i=e[i].next) {
            v=e[i].to;
            ans[v]=max(ans[v],ans[u]+1);
        }
    }
    for(int i=1; i<=top; i++) printf("%d\n",ans[i]);
    return 0;
}

时间: 2024-10-08 22:06:23

拓扑相关题目的相关文章

LeetCode: Palindrome 回文相关题目

LeetCode: Palindrome 回文相关题目汇总 LeetCode: Palindrome Partitioning 解题报告 LeetCode: Palindrome Partitioning II 解题报告 Leetcode:[DP]Longest Palindromic Substring 解题报告 LeetCode: Valid Palindrome 解题报告

九度 Online Judge 之《剑指 Offer》一书相关题目解答

前段时间准备华为机试,正好之前看了一遍<剑指 Offer>,就在九度 Online Judge 上刷了书中的题目,使用的语言为 C++:只有3题没做,其他的都做了. 正如 Linus Torvalds 所言“Talk is cheap, show me the code!",详见托管在 Github 的源码:点击打开链接(核心部分有注释). 难度总结:有些可以不必要像书中那样保存中间结果,直接输出,也就可以不使用书中的算法:有些题目在书中题目的基础上加了更多的要求,也更难实现一点.

搜索相关题目

1. 并查集相关的题目 2. Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured by flipping all 'O''s into 'X''s in that surrounded region. Example X X X X X O O X X X O X X O X X After capture a

递归相关题目

二叉树的镜像 题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / 6 10 / \ / 5 7 9 11 镜像二叉树 8 / 10 6 / \ / 11 9 7 5 /** public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } */ publi

算法题16 二分查找及相关题目

二分查找思想就是取中间的数缩小查找范围,对应不同的题目变形,在取到中间数mid确定下一个查找范围时也有不同,左边界有的low=mid+1,也可能low=mid,右边界有的high=mid-1,也有可能high=mid. 对于一个排序数组来说二分查找的时间复杂度是O(logn) 1. 二分查找法 1 int BinarySearch(int arr[],int len,int target) 2 { 3 if (arr==NULL||len<=0) 4 throw std::exception(&qu

二叉树相关题目总结

1. 简要介绍   关于二叉树问题,由于其本身固有的递归属性,通常我们可以用递归算法来解决.(<编程之美>,P253) 总结的题目主要以leetcode题目为主. 2. 测试用例 空树,只有节点的二叉树,只有左子树/右子树的二叉树,既有左子树右有右子树的二叉树. 3. 二叉树的遍历 遍历简介: 二叉树的遍历 分层遍历:二叉树分层遍历 前序遍历:[LeetCode] Binary Tree Preorder Traversal 中序遍历:[LeetCode] Binary Tree Inorde

已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)

1.文字描述: 已知一颗二叉树的前序(后序)遍历序列和中序遍历序列,如何构建这棵二叉树? 以前序为例子: 前序遍历序列:ABCDEF 中序遍历序列:CBDAEF 前序遍历先访问根节点,因此前序遍历序列的第一个字母肯定就是根节点,即A是根节点:然后,由于中序遍历先访问左子树,再访问根节点,最后访问右子树,所以我们找到中序遍历中A的位置,然后A左边的字母就是左子树了,也就是CBD是根节点的左子树:同样的,得到EF为根节点的右子树. 将前序遍历序列分成BCD和EF,分别对左子树和右子树应用同样的方法,

剑指offer题目系列三(链表相关题目)

本篇延续上一篇剑指offer题目系列二,介绍<剑指offer>第二版中的四个题目:O(1)时间内删除链表结点.链表中倒数第k个结点.反转链表.合并两个排序的链表.同样,这些题目并非严格按照书中的顺序展示的,而是按自己学习的顺序,每个题目包含了分析和代码. 9.O(1)时间内删除链表结点 题目: 在O(1)时间内删除链表结点.给定单链表的头指针和一个结点指针,定义一个方法在O(1)时间内删除该结点. 单链表的定义如下: 解答: 单向链表删除一个结点,最直观的想法是从链表的头结点开始顺序遍历查找要

对动态规划算法的理解及相关题目分析

1.对动态规划算法的理解 (1)基本思想: 动态规划算法的基本思想与分治法类似:将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中得到原问题的解.但是,与分治法不同的是,为了避免重复多次计算子问题,动态规划算法用一个表记录所有已解决的子问题的答案,不管该子问题以后是否被利用,只要它被计算过,就将其结果填入表中. (2)设计动态规划算法的步骤: ①找出最优解的性质,并刻画其结构特征 ②递归地定义最优值 ③以自底向上的方式计算最优值 ④根据计算最优值时得到的信息构造最优解 (3)