Uva 10305 - Ordering Tasks(拓扑排序)

题目链接 https://vjudge.net/problem/UVA-10305


John has n tasks to do. Unfortunately, thetasks are not independent and the execution of one task is only possible ifother tasks have already been executed.

 

Input

The input will consist of several instancesof the problem. Each instance begins with a line containing two integers, 1 ≤ n≤ 100 and m. n is the number of tasks (numbered from 1 to n) and m is thenumber of direct precedence relations between tasks. After this, there will bem lines with two integers i and j, representing the fact that task i must beexecuted before task j. An instance with n = m = 0 will finish the input.

 

Output For each instance, print a line withn integers representing the tasks in a possible order of execution.

 

Sample Input

4 1 

2 2 

3 1 

3 1 

5 0 

0

Sample Output

3

 

 【题意】

 紫书167页例题。假设有n个变量,还有m个二元组(u,v),分别表示变量u<v,那么所有变量从小到大排列起来应该是什么样的呢假设有n个变量,还有m个二元组(u,v),分别表示变量u<v,那么所有变量从小到大排列起来应该是什么样的呢?例如有四个变量a,b,c,d,若已知a<b,c<b,d<c,则这四个变量的排序可能是a<d<c<b,尽管还有其他可能,但你只需找出其中的一个即可。


 

【思路】

 裸的拓扑排序问题,可以用数据结构书上讲的那种方法:选择一个0入度的顶点,删除它的所有有向边,再在剩余的结点中选择另一个0入度顶点,重复这个过程,选择顶点的顺序就是拓扑排序所得的序列。这里有一个更为简便的方法,仅仅需要dfs即可实现,和普通的dfs有所不同的是访问数组有三个值。used[v]==0表示顶点v没有被访问过,used[v]==1表示v的所有子孙和它本身都已经被访问过,used[v]==-1表示v的子孙正在被访问,即以v为根结点的dfs正在执行。

这样一来,即可判断有向图中是否有环,还能在没有环时求出拓扑序列。

坑点:判断m和n同时为0的条件容易想错。是(m||n)而不是(m&&n),画个真值表就明白了。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 150;

int m, n;
int from, to;
vector<int> G[maxn];
vector<int> ans;
int used[maxn];

void init() {
	ans.clear();
	memset(used, 0, sizeof(used));
	for (int i = 0; i < maxn; i++) G[i].clear();
}

bool dfs(int v) {
	used[v] = -1;
	for (int i = 0; i < G[v].size(); i++) {
		int u = G[v][i];
		if (-1 == used[u]) return false;
		if (0 == used[u] && !dfs(u)) return false;
	}
	used[v] = 1;
	ans.push_back(v);
	return true;
}

bool toposort() {
	for (int i = 1; i <= n; i++) {
		if (!used[i]) 
			if (!dfs(i)) return false;
	}
	return true;
}

int main() {
	while (scanf("%d%d", &n, &m) == 2 && (n || m)) {
		init();
		for (int i = 0; i < m; i++) {
			scanf("%d%d", &from, &to);
			G[from].push_back(to);
		}
		
		if (!toposort()) continue;
		
		reverse(ans.begin(), ans.end());
		for (int i = 0; i < ans.size(); i++) {
			printf("%d%c", ans[i], i + 1 == ans.size() ? '\n' : ' ');
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值