拓扑排序

#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;
}
原文地址:https://www.cnblogs.com/downrainsun/p/10327531.html