結果
| 問題 |
No.583 鉄道同好会
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2023-02-14 12:54:57 |
| 言語 | Go (1.23.4) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 5,942 bytes |
| コンパイル時間 | 14,287 ms |
| コンパイル使用メモリ | 233,584 KB |
| 実行使用メモリ | 20,640 KB |
| 最終ジャッジ日時 | 2024-07-17 01:54:19 |
| 合計ジャッジ時間 | 16,168 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | WA * 3 |
| other | WA * 16 |
ソースコード
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func yukicoder() {
// https://yukicoder.me/problems/no/583
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var n, m int
fmt.Fscan(in, &n, &m)
et := NewEulerianTrail(n, false)
for i := 0; i < m; i++ {
var a, b int
fmt.Fscan(in, &a, &b)
et.AddEdge(a, b)
}
res := et.EnumerateSemiEulerianTrail(0)
if len(res) == 1 {
fmt.Fprintln(out, "YES")
} else {
fmt.Fprintln(out, "NO")
}
}
func main() {
// https: //www.luogu.com.cn/problem/P7771
// 有向图字典序最小的欧拉路径
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var n, m int
fmt.Fscan(in, &n, &m)
edges := make([][]int, 0, m)
et := NewEulerianTrail(n+1, true)
for i := 0; i < m; i++ {
var a, b int
fmt.Fscan(in, &a, &b)
et.AddEdge(a, b)
edges = append(edges, []int{a, b})
}
res := et.EnumerateSemiEulerianTrail(-1)
if len(res) != 1 {
fmt.Fprintln(out, "No")
} else {
ids := res[0]
path := make([]int, 0, len(ids)+1)
for i, id := range ids {
a, b := edges[id][0], edges[id][1]
path = append(path, a)
if i == len(ids)-1 {
path = append(path, b)
}
}
for _, v := range path {
fmt.Fprint(out, v, " ")
}
}
}
type EulerianTrail struct {
g [][][2]int
es [][2]int
m int
usedVertex []bool
usedEdge []bool
deg []int
directed bool
}
func NewEulerianTrail(n int, directed bool) *EulerianTrail {
res := &EulerianTrail{
g: make([][][2]int, n),
usedVertex: make([]bool, n),
deg: make([]int, n),
directed: directed,
}
return res
}
func (e *EulerianTrail) AddEdge(a, b int) {
e.es = append(e.es, [2]int{a, b})
e.g[a] = append(e.g[a], [2]int{b, e.m})
if e.directed {
e.deg[a]++
e.deg[b]--
} else {
e.g[b] = append(e.g[b], [2]int{a, e.m})
e.deg[a]++
e.deg[b]++
}
e.m++
}
// 枚举所有连通块的`欧拉回路`,返回边的编号.
// 如果连通块内不存在欧拉回路,返回空.
// lex: -1: 字典序最小, 0: 任意, 1: 字典序最大.
func (e *EulerianTrail) EnumerateEulerianTrail(lex int8) [][]int {
if e.directed {
for _, d := range e.deg {
if d != 0 {
return [][]int{}
}
}
} else {
for _, d := range e.deg {
if d&1 == 1 {
return [][]int{}
}
}
}
e.sortNeighborsByLex(lex)
e.usedEdge = make([]bool, e.m)
res := [][]int{}
for i := 0; i < len(e.g); i++ {
if !e.usedVertex[i] && len(e.g[i]) > 0 {
res = append(res, e.work(i))
}
}
return res
}
// 枚举所有连通块的`欧拉路径`(半欧拉回路),返回边的编号.
// 如果连通块内不存在欧拉路径,返回空.
// lex: -1: 字典序最小, 0: 任意, 1: 字典序最大.
func (e *EulerianTrail) EnumerateSemiEulerianTrail(lex int8) [][]int {
e.sortNeighborsByLex(lex)
uf := newUnionFindArray(len(e.g))
for _, es := range e.es {
uf.Union(es[0], es[1])
}
group := make([][]int, len(e.g))
for i := 0; i < len(e.g); i++ {
group[uf.Find(i)] = append(group[uf.Find(i)], i)
}
res := [][]int{}
e.usedEdge = make([]bool, e.m)
for _, vs := range group {
if len(vs) == 0 {
continue
}
latte, malta := -1, -1
if e.directed {
for _, p := range vs {
if abs(e.deg[p]) > 1 {
return [][]int{}
} else if e.deg[p] == 1 {
if latte >= 0 {
return [][]int{}
}
latte = p
}
}
} else {
for _, p := range vs {
if e.deg[p]&1 == 1 {
if latte == -1 {
latte = p
} else if malta == -1 {
malta = p
} else {
return [][]int{}
}
}
}
}
var cur []int
if latte == -1 {
cur = e.work(vs[0])
} else {
cur = e.work(latte)
}
if len(cur) > 0 {
res = append(res, cur)
}
}
return res
}
func (e *EulerianTrail) GetEdge(index int) (int, int) {
return e.es[index][0], e.es[index][1]
}
func (e *EulerianTrail) work(s int) []int {
st := [][2]int{}
ord := []int{}
st = append(st, [2]int{s, -1})
for len(st) > 0 {
index := st[len(st)-1][0]
e.usedVertex[index] = true
if len(e.g[index]) == 0 {
ord = append(ord, st[len(st)-1][1])
st = st[:len(st)-1]
} else {
e_ := e.g[index][len(e.g[index])-1]
e.g[index] = e.g[index][:len(e.g[index])-1]
if e.usedEdge[e_[1]] {
continue
}
e.usedEdge[e_[1]] = true
st = append(st, [2]int{e_[0], e_[1]})
}
}
ord = ord[:len(ord)-1]
for i, j := 0, len(ord)-1; i < j; i, j = i+1, j-1 {
ord[i], ord[j] = ord[j], ord[i]
}
return ord
}
func (e *EulerianTrail) sortNeighborsByLex(useLex int8) {
if useLex == -1 {
e.sortNeighbors(true)
} else if useLex == 1 {
e.sortNeighbors(false)
}
}
// 排在后面的边先出来.
func (e *EulerianTrail) sortNeighbors(reverse bool) {
for _, es := range e.g {
sort.Slice(es, func(i, j int) bool {
if reverse {
return es[i][0] > es[j][0]
}
return es[i][0] < es[j][0]
})
}
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
func newUnionFindArray(n int) *unionFindArray {
parent, rank := make([]int, n), make([]int, n)
for i := 0; i < n; i++ {
parent[i] = i
rank[i] = 1
}
return &unionFindArray{
Part: n,
size: n,
Rank: rank,
parent: parent,
}
}
type unionFindArray struct {
size int
Part int
Rank []int
parent []int
}
func (ufa *unionFindArray) Union(key1, key2 int) bool {
root1, root2 := ufa.Find(key1), ufa.Find(key2)
if root1 == root2 {
return false
}
if ufa.Rank[root1] > ufa.Rank[root2] {
root1, root2 = root2, root1
}
ufa.parent[root1] = root2
ufa.Rank[root2] += ufa.Rank[root1]
ufa.Part--
return true
}
func (ufa *unionFindArray) Find(key int) int {
for ufa.parent[key] != key {
ufa.parent[key] = ufa.parent[ufa.parent[key]]
key = ufa.parent[key]
}
return key
}
func (ufa *unionFindArray) IsConnected(key1, key2 int) bool {
return ufa.Find(key1) == ufa.Find(key2)
}
func (ufa *unionFindArray) Size(key int) int {
return ufa.Rank[ufa.Find(key)]
}