zoukankan      html  css  js  c++  java
  • 拓扑排序

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<vector>
    
    using namespace std;
    const int maxm = 105;
    
    vector<int> ve[maxm];
    int indeg[maxm], n, m, num, a[maxm], x, y;
    queue<int> q;
    
    void topsort() {
    while(!q.empty())q.pop();
    num = 0;
    for(int i = 1; i <= n; i++) {
        if(!indeg[i]) q.push(i);
    }
    while(!q.empty()) {
        int nx = q.front();
        a[num++] = nx;
        q.pop();
        for(int i = 0; i < ve[nx].size(); i++) {
            if(--indeg[ ve[nx][i] ] == 0) q.push(ve[nx][i]);
        }
    }
    }
    //num小于n的话说明有环,因为环中的元素进不去队列。等于n说明没环
    int main() {
    while(~scanf("%d%d", &n, &m)) {
        if(n == 0 && m  == 0) break;
        memset(indeg, 0, sizeof(indeg));
        memset(a, 0, sizeof(a));
        for(int i = 1; i <= n; i++) {
            ve[i].clear();
        }
        while(m--) {
            scanf("%d%d", &x, &y);
            ve[x].push_back(y);
            indeg[y]++;
        }
        topsort();
        for(int i = 0; i < n; i++) {
            if(i == 0) printf("%d", a[i]);
            else printf(" %d", a[i]);
        }
        printf("
    ");
    }
    
    }

    找入度为零的点,然后一个一个存,一般用于很多任务,给出几个优先级, 然后得到总的顺序。

    https://vjudge.net/contest/280900#problem/A习题

    难题  https://vjudge.net/contest/280900#problem/H 

    Sorting It All Out
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 21532   Accepted: 7403
    Description

    An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B, C, D implies that A < B, B < C and C < D. in this problem, we will give you a set of relations of the form A < B and ask you to determine whether a sorted order has been specified or not.
    Input

    Input consists of multiple problem instances. Each instance starts with a line containing two positive integers n and m. the first value indicated the number of objects to sort, where 2 <= n <= 26. The objects to be sorted will be the first n characters of the uppercase alphabet. The second value m indicates the number of relations of the form A < B which will be given in this problem instance. Next will be m lines, each containing one such relation consisting of three characters: an uppercase letter, the character "<" and a second uppercase letter. No letter will be outside the range of the first n letters of the alphabet. Values of n = m = 0 indicate end of input.
    Output

    For each problem instance, output consists of one line. This line should be one of the following three: 

    Sorted sequence determined after xxx relations: yyy...y. 
    Sorted sequence cannot be determined. 
    Inconsistency found after xxx relations. 

    where xxx is the number of relations processed at the time either a sorted sequence is determined or an inconsistency is found, whichever comes first, and yyy...y is the sorted, ascending sequence. 
    Sample Input

    4 6
    A<B
    A<C
    B<C
    C<D
    B<D
    A<B
    3 2
    A<B
    B<A
    26 1
    A<Z
    0 0
    Sample Output

    Sorted sequence determined after 4 relations: ABCD.
    Inconsistency found after 2 relations.
    Sorted sequence cannot be determined.

    分析:

    这题典型的拓扑排序,但是有点变化。

    题目样例的三种输出分别是:

    1. 在第x个关系中可以唯一的确定排序,并输出。

    2. 在第x个关系中发现了有回环(Inconsisitency矛盾)

    3.全部关系都没有发现上面两种情况,输出第3种.

    那么对于给定的m个关系,一个个的读进去,每读进去一次就要进行一次拓扑排序,如果发现情况1和情况2,那么就不用再考虑后面的那些关系了,但是还要继续读完后面的关系(但不处理)。如果读完了所有关系,还没有出现情况1和情况2,那么就输出情况3.

    拓扑排序有两种方法,一种是算法导论上的,一种是用贪心的思想,这题用贪心的思想做更好。

    贪心的做法:

    1. 找到所有入度为0的点, 加入队列Q

    2.取出队列Q的一个点,把以这个点为起点,所有它的终点的入度都减1. 如果这个过程中发现经过减1后入度变为0的,把这个点加入队列Q。

    3.重复步骤2,直到Q为空。

    这个过程中,如果同时有多个点的入度为0,说明不能唯一确定关系。

    如果结束之后,所得到的经过排序的点少于点的总数,那么说明有回环。

    题目还需要注意的一点:如果边(u,v)之前已经输入过了,那么之后这条边都不再加入。

    //这一题的话一开始是想只有n个字母都进去了才能判冲突,但是就算没全进去也有可能有冲突,
    //然后因为就算没有全进去也可以用拓扑排序来判断,因为那些还没出现的字母,他们的入度都为零,所以也会进队,所以也可以通过判是否等于n来判断是否有冲突。
    //另外一点就是顺序不一定是字母序,严格按照得到的结果来输出。
    #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; vector<int> ve[30]; int indeg[30], indeg1[30]; int findx(int x, int y){ for(int i = 0; i < ve[x].size(); i++) { if(ve[x][i] == y) return 1; } return 0; } int n, m, x, y, res[30], now; queue<int> q; int topsort() { while(!q.empty()) q.pop(); now = 0; for(int i = 0; i < n; i++) { if(indeg[i] == 0) q.push(i); } int unio = 0; while(!q.empty()) { if(q.size() > 1) unio = 1; //说明有两个入度为零的,则无法确定。 int t = q.front(); res[now++] = t; q.pop(); for(int i = 0; i < ve[t].size(); i++) { if(--indeg[ ve[t][i] ] == 0) { q.push(ve[t][i]); } } } if(now < n) return 1; if(unio) return 2; return 3; } char ch[5]; int main() { while(~scanf("%d%d", &n, &m)) { if(n == 0 && m == 0) break; memset(indeg, 0, sizeof(indeg)); for(int i = 0; i < n; i++) { ve[i].clear(); } int done = 0; int flag = 0; int ant = 0; int stop = -1; while(m--) { scanf("%s", ch); if(done == 1) continue; ant++; x = ch[0] - 'A'; y = ch[2] - 'A'; if(ch[1] == '<') { if(!findx(x, y)) { indeg[y]++; ve[x].push_back(y); } } else { // x = ch[0] - 'A'; // y = ch[2] - 'A'; if(!findx(y, x)) { indeg[x]++; ve[y].push_back(x); } } memcpy(indeg1, indeg, sizeof(indeg)); flag = topsort(); memcpy(indeg, indeg1, sizeof(indeg1)); if(flag != 2) { done = 1; stop = ant; } } if(flag == 1) { printf("Inconsistency found after %d relations. ", stop); } else if(flag == 3) { printf("Sorted sequence determined after %d relations: ", stop); for(int i = 0; i < now; i++) { printf("%c", 'A' + res[i]); } printf(". "); } else { printf("Sorted sequence cannot be determined. "); } } return 0; }

    Andrew and Taxi

     https://vjudge.net/contest/283149#problem/G

    题目意思是要n条路,翻转几条路使得没有环,求翻转的边中的最大值,然后要我们最小化这个最大值。

    思路:先二分一个最大值出来,然后把这些比他大的边加进来,然后进行拓扑排序来判环,并得到每条边的拓扑序。

    (拓扑序的一个重要性质就是拓扑排序之后,那么在有向边中,起点的拓扑序一定小于终点的拓扑序。)

    然后如果没环的话往左走,减小最大值。有环往右走,最后可以得到一个答案。

    之后对于比他小的,因为不限翻转的次数,所以只要碰到拓扑序反了的就把这条边反过来。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    
    const int maxm = 1e5 + 5;
    struct NODE {
    int u, v, c;
    } node[maxm];
    int indeg[maxm], a[maxm];
    vector<int> ve[maxm], ans;
    int n, m;
    
    int top(int x) {
    memset(indeg, 0, sizeof(indeg));
    memset(a, 0, sizeof(a));
    for(int i = 1; i <= n; i++) {
        ve[i].clear();
    }
    for(int i = 1; i <= m; i++) {
        if(node[i].c > x) {
            ve[ node[i].u ].push_back(node[i].v);
            indeg[ node[i].v ]++;
        }
    }
    //for(int i = 1; i <= n; i++) {
    //    printf("%d
    ", indeg[i]);
    //}
    queue<int> q;
    int num = 0;
    for(int i = 1; i <= n; i++) {
        if(!indeg[i]) {
            q.push(i);
        }
    }
    while(!q.empty()) {
    //    printf(" is 
    ");
        int now = q.front();
        q.pop();
        a[now] = num++; // 拓扑序
    //printf("%d
    ", now);
        for(int i = 0; i < ve[now].size(); i++) {
            if(--indeg[ ve[now][i] ] == 0) {
                q.push(ve[now][i]);
    
            }
        }
    }
    if(num == n) return true; //用于判环,还可以判断每一条边的入度是否为零,如果大于等于一个不为零,则有环。
    return false;
    }
    
    int main() {
    scanf("%d%d", &n, &m);
    int minn = 1e9 + 7;
    ans.clear();
    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d", &node[i].u, &node[i].v, &node[i].c);
    }
    int l = 0, r = minn, mid = 0, res = 0;
    while(l <= r) {
        mid = (l + r) / 2;
        if(top(mid)) {
            r = mid - 1;
            res = mid;
        }
        else {
            l = mid + 1;
        }
    }
    top(res);
    for(int i = 1; i <= m; i++) {
        if(a[ node[i].u ] > a[ node[i].v ] && node[i].c <= res) {
            ans.push_back(i);
        }
    }
    printf("%d %d
    ", res, ans.size());
    for(int i = 0; i < ans.size(); i++) {
        if(i == 0) printf("%d", ans[i]);
        else printf(" %d", ans[i]);
    }
    printf("
    ");
    
    return 0;
    }
  • 相关阅读:
    八皇后问题
    Catalan数与出栈顺序个数,Java编程模拟
    推荐系统中的协同过滤
    集成学习
    背包问题
    逆波兰表达式
    [leetcode]775. Global and Local Inversions
    [LeetCode]Minimum Moves to Equal Array Elements1,2
    链接属性
    常用表格属性
  • 原文地址:https://www.cnblogs.com/downrainsun/p/10327531.html
Copyright © 2011-2022 走看看