#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("\n");
}
}
找入度为零的点,然后一个一个存,一般用于很多任务,给出几个优先级, 然后得到总的顺序。
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.\n", 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(".\n");
}
else {
printf("Sorted sequence cannot be determined.\n");
}
}
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\n", 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 \n");
int now = q.front();
q.pop();
a[now] = num++; // 拓扑序
//printf("%d\n", 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\n", res, ans.size());
for(int i = 0; i < ans.size(); i++) {
if(i == 0) printf("%d", ans[i]);
else printf(" %d", ans[i]);
}
printf("\n");
return 0;
}
来源:https://www.cnblogs.com/downrainsun/p/10327531.html