拓扑相关题目

Posted 云深不知处

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拓扑相关题目相关的知识,希望对你有一定的参考价值。

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

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;
}
View Code

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;
}
View Code

 

以上是关于拓扑相关题目的主要内容,如果未能解决你的问题,请参考以下文章

「拓扑排序」可达性统计

拓扑排序,YYDS!

题目1450:产生冠军(拓扑排序简单题)

题目1449:确定比赛名次(拓扑排序问题)

图论-拓扑排序详解

图相关算法