golang算法:有向图的拓扑序列

7 篇文章 0 订阅

题目描述

给定一个n个点m条边的有向图,点的编号是1到n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出-1。

若一个由图中所有点构成的序列A满足:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。

输入格式
第一行包含两个整数n和m

接下来m行,每行包含两个整数x和y,表示存在一条从点x到点y的有向边(x, y)。

输出格式
共一行,如果存在拓扑序列,则输出拓扑序列。

否则输出-1。

数据范围
1≤n,m≤105

输入样例:

1 2
2 3
1 3

输出样例:
1 2 3

Go 代码

方法1,多创建一个跟队列q一样的切片,用来保存结果
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

const N = 100010

var (
	n, m ,idx int
	e,ne,h[N]int
	d [N]int //记录每个点的 "度",有"出度"和"入度"
	q,qq []int //bfs的队列
	)

func add(a,b int)  {
	e[idx] = b
	ne[idx] = h[a]
	h[a] = idx
	idx ++
}
func readline(r *bufio.Reader)[]int  {
	s,_:=r.ReadString('\n')
	ss :=strings.Fields(s)
	res :=make([]int,len(ss))
	for i,v :=range ss{
		res[i],_ = strconv.Atoi(v)
	}
	return res
}

func topsort()bool  {
	for i:=1;i<=n;i++{
		if d[i]==0{ // 将入度为0的点插入到队列中
		q =append(q,i)
		qq =append(qq,i)
		}
	}
	for len(q)>0{
		t :=q[0]
		q = q[1:]
		for i:=h[t];i!=-1;i=ne[i]{ // 枚举t的所有出边 t->j
			j:=e[i] // 删除t->j这条出边
			d[j]--
			if d[j]==0{
				// 放入队列
				q =append(q,j)
				qq =append(qq,j)
			}
		}
	}
	return len(qq)==n
}
func main() {
	fmt.Scan(&n, &m)
    r :=bufio.NewReader(os.Stdin)

	for i:=0;i<N;i++{
		h[i]=-1
	}

	for i:=0;i<m;i++{
		in :=readline(r)
		a,b :=in[0],in[1]
		add(a,b)
		d[b]++ // 点b增加"入度"
	}
	if topsort(){
		for i:=0;i<n;i++{
			fmt.Print(qq[i]," ")
		}
	}else{
	    fmt.Println(-1)
	}

}


算法2 只创建一个模拟队列q的切片

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

const N = 100010

var (
	n, m ,idx int
	e,ne,h[N]int
	d [N]int //记录每个点的 "度",有"出度"和"入度"
	q[N]int //bfs的队列
	)

func add(a,b int)  {
	e[idx] = b
	ne[idx] = h[a]
	h[a] = idx
	idx ++
}
func readline(r *bufio.Reader)[]int  {
	s,_:=r.ReadString('\n')
	ss :=strings.Fields(s)
	res :=make([]int,len(ss))
	for i,v :=range ss{
		res[i],_ = strconv.Atoi(v)
	}
	return res
}
func topsort()bool  {
	hh,tt :=0,-1 // 头尾
	for i:=1;i<=n;i++{
		if d[i]==0{ // 将入度为0的点插入到队列中
			tt++
			q[tt] = i
		}
	}
	for hh<=tt{
		t :=q[hh]
		hh++
		for i:=h[t];i!=-1;i=ne[i]{ // 枚举t的所有出边 t->j
			j:=e[i] // 删除t->j这条出边
			d[j]--
			if d[j]==0{
				// 放入队列
				tt++
				q[tt] = j
			}
		}
	}
	return tt==n-1
}
func main() {
// 	fmt.Scan(&n, &m)
    r :=bufio.NewReader(os.Stdin)
	//fmt.Scan(&n, &m)
	w:= readline(r)
	n,m = w[0],w[1]
	for i:=0;i<N;i++{
		h[i]=-1
	}
// 	r :=bufio.NewReader(os.Stdin)
	for i:=0;i<m;i++{
		in :=readline(r)
		a,b :=in[0],in[1]
		add(a,b)
		d[b]++ // 点b增加"入度"
	}
	if topsort(){
		for i:=0;i<n;i++{
			fmt.Print(q[i]," ")
		}
	}else{
	    fmt.Println(-1)
	}

}

时间复杂度 O(m+n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值