【编程题】【未知出处】任务排序 / 拓扑排序

知识点:拓扑排序

一、只要求满足偏序的拓扑排序

输入:几个偏序

n=5 # 节点个数
m=4 # 偏序个数
12
23
13
15

输出:一种排序方式或不能排序

1 4 2 5 3

思路:存储输入的拓扑关系,定义数组记录每一个点状态。对状态显示还未被遍历的点进行DFS(),遍历该点以及与该点有直接拓扑关系的点。在DFS过程中将元素压入存放拓扑结果的vector结构ans。

以下代码只是为了记录思路,代码C/python混用,不可运行

vector<int> a[100];
int mark[100];   //为0表示还未遍历(初始)
vector<int> topo; 

bool DFS(int u) # ***** 例如当前遍历到节点1(a[1]=[2,3,5])
{
	mark[u]=-1;    //为-1表示正在遍历 # 另mark[1] = -1
	for(int i=0;i<a[u].size();i++) # 对于[2,3,5]的每一个,//再次遇到正在遍历中的,返回false 
		if(mark[a[u][i]]==-1) # 即 v = a[u][I] = u # 若存在偏序[u,u]或[u,v][v,u]或[u,m][m,v][v,u]则无法构成拓扑排序
			return false;
		elif(mark[a[u][i]]==0&&DFS(a[u][i])==false) //未遍历则开始遍历,并对返回值做出判断 
    		return false; # 若v可以继续遍历 但以1为首的偏序不可以继续遍历,依然false
	
	mark[u]=1;              //该值遍历完成  //mark为1表示已经遍历该节点及其子节点
	topo.push_back(u);     //放入topo序列中 
	return true;
}
 
int main()
{
	int n,m;
		for(int i=1;i<=m;i++)  # 对于输入的每一个偏序(u,v),key为u,value为v,存下来
			a[u].push_back(v); 
		flag=true; # 保存好所有的偏序后,默认可以构成拓扑排序

		for(int i=1;i<=n;i++):        # 对所有的节点依次遍历
			if(mark[i]==1) continue;   //已经遍历过,直接跳 
			if(DFS(i)==false):       //有一个false即不存在 *****
				flag=false;

		if(flag == true):
			print topo[::-1] //拓扑排序从后往前打印 
		else
    		cout<<"not exist."<<endl;
}
--------------------- 
作者:mavises 
来源:CSDN 
原文:https://blog.csdn.net/mavises/article/details/81706227 
版权声明:本文为博主原创文章,转载请附上博文链接!

记录另一种,差别不大,详细讲解在注释中:

int c[maxn];
int topo[maxn],t,G[maxn][maxn],n;
bool dfs(int u)
{
    c[u]=-1; # 当前节点置-1,表示正在遍历
    for(int v=1;v<=n;v++) # 对于每一个节点
        if(G[u][v]) # 如果这个节点存在偏序
        {
            if(c[v]<0)return false; # 防止[u,u]出现
            elif(!c[v] && !dfs(v))return false ; # 当前节点未遍历可以遍历,但下一个节点不能遍历,依旧是false
        }
    c[u]=1;topo[--t]=u; # 当前节点已遍历
    return true;
}
bool toposort() # 进行topo排序
{
    t=n;
    memset(c,0,sizeof(c));
    for(int u=1;u<=n;u++) if(!c[u])
        if(!dfs(u))return false;
    return true;
}
int main()
{
    int m,i;
    while(scanf("%d%d",&n,&m),n || m)
    {
        int u,v;
        memset(G,0,sizeof(G));
        for(i = 0 ; i < m ; i++)
        {
            scanf("%d%d",&u,&v);
            G[u][v] = 1; # 偏序的存放,有偏序关系存为1
        }
        if(toposort()) # 进行topo排序,排好了之后输出
        {
            for(i = 0; i < n-1; i++)
                printf("%d ",topo[i]);
        }
    }
    return 0;
}
--------------------- 
作者:01的世界 
来源:CSDN 
原文:https://blog.csdn.net/loveyou11111111/article/details/46426677 
版权声明:本文为博主原创文章,转载请附上博文链接!

二、只输出从0到N的一条路径

def DFS(u, price):
	mark[u] = -1
	for v, p in G[u]:
		print(u, v)
		if mark[v] == -1:
			return False
		if mark[v] == 0 and not DFS(v, p):
			return False
		break
	mark[u] = 1
	topu.append(price)
	pp.append([u, price])
	return True

# 构建有向图
G = [[] for _ in range(N)]
for m in M:
	G[m[0]].append([m[1], m[2]]) # tupo排序 加入到达地点以及票价

result = [] 
# 每天
	mark = [0] * (N)
	topu = []
	pp = []
	# minresult = float('inf')
	start, end1, end2, price = Q[day]
	for end in range(end1, end2 + 1):
		G[start].append([end, price])
	print(G)
	# 默认可以拓扑排序
	flag = True
	# for i in range(N): # 对所有的节点依次遍历
	for i in range(1):  # 对所有的节点依次遍历
		if mark[i] == 1:
			continue;   # 已经遍历过,直接跳 
		if DFS(i, 0) == False: # 有一个false即不存在 *****
			flag = False;

	if flag == True:
		result.append(sum(topu))
	else:
		result.append(-1)
print result

 

三、更多要求的拓扑排序

上文生成的拓扑排序是仅仅满足了偏序的,编程题目中有时可能会有更多的要求,比如每个节点是一个任务,每个任务有自己的权重,然后要求权重高的尽量往前排等等

待更新 ****(欢迎补充)

 

三、leetcode练习题

210:拓扑排序: https://leetcode-cn.com/problems/course-schedule-ii/

官方解法https://leetcode-cn.com/problems/course-schedule-ii/solution/ke-cheng-biao-ii-by-leetcode/

207:是210的简化版,两道题都可以使用计算入度的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值