結果

問題 No.2674 k-Walk on Bipartite
ユーザー shogo314shogo314
提出日時 2024-03-15 23:22:19
言語 C++23
(gcc 12.3.0 + boost 1.83.0)
結果
RE  
実行時間 -
コード長 33,379 bytes
コンパイル時間 3,235 ms
コンパイル使用メモリ 277,932 KB
実行使用メモリ 32,584 KB
最終ジャッジ日時 2024-09-30 02:56:44
合計ジャッジ時間 8,802 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 RE -
testcase_01 AC 1 ms
6,816 KB
testcase_02 AC 2 ms
6,816 KB
testcase_03 AC 2 ms
6,820 KB
testcase_04 RE -
testcase_05 RE -
testcase_06 AC 2 ms
6,820 KB
testcase_07 AC 91 ms
20,444 KB
testcase_08 RE -
testcase_09 AC 73 ms
20,236 KB
testcase_10 RE -
testcase_11 AC 57 ms
15,812 KB
testcase_12 RE -
testcase_13 AC 75 ms
17,884 KB
testcase_14 RE -
testcase_15 AC 164 ms
22,468 KB
testcase_16 RE -
testcase_17 AC 112 ms
17,236 KB
testcase_18 AC 47 ms
13,832 KB
testcase_19 AC 92 ms
18,424 KB
testcase_20 RE -
testcase_21 AC 109 ms
18,516 KB
testcase_22 AC 145 ms
23,324 KB
testcase_23 AC 2 ms
5,248 KB
testcase_24 RE -
testcase_25 RE -
testcase_26 AC 2 ms
6,820 KB
testcase_27 AC 2 ms
5,248 KB
testcase_28 AC 2 ms
5,248 KB
testcase_29 AC 2 ms
5,248 KB
testcase_30 AC 2 ms
5,248 KB
testcase_31 AC 3 ms
5,248 KB
testcase_32 RE -
testcase_33 RE -
testcase_34 AC 2 ms
5,248 KB
testcase_35 RE -
testcase_36 AC 2 ms
5,248 KB
testcase_37 AC 2 ms
5,248 KB
testcase_38 RE -
権限があれば一括ダウンロードができます

ソースコード

diff #

#line 2 "/home/shogo314/cpp_include/ou-library/graph_util.hpp"

/**
 * @file graph_util.hpp
 * @brief グラフに関する関数
 */

#include <stack>

#line 2 "/home/shogo314/cpp_include/ou-library/graph.hpp"

#include <iostream>
#include <limits>
#include <queue>
#include <vector>

/**
 * @brief グラフの汎用クラス
 *
 * @tparam Cost 辺のコストの型
 */
template <typename Cost=int>
struct Graph {
    /**
     * @brief 有向辺の構造体
     *
     * operator int()を定義しているので、int型にキャストすると勝手にdstになる
     * 例えば、
     * for (auto& e : g[v]) をすると、vから出る辺が列挙されるが、
     * for (int dst : g[v]) とすると、vから出る辺の行き先が列挙される
     */
    struct Edge {
        int src; //!< 始点
        int dst; //!< 終点
        Cost cost; //!< コスト
        int id; //!< 辺の番号(追加された順、無向辺の場合はidが同じで方向が逆のものが2つ存在する)
        Edge() = default;
        Edge(int src, int dst, Cost cost=1, int id=-1) : src(src), dst(dst), cost(cost), id(id) {}
        operator int() const { return dst; }
    };

    int n; //!< 頂点数
    int m; //!< 辺数
    std::vector<std::vector<Edge>> g; //!< グラフの隣接リスト表現

    /**
     * @brief デフォルトコンストラクタ
     */
    Graph() : n(0), m(0), g(0) {}
    /**
     * @brief コンストラクタ
     * @param n 頂点数
     */
    explicit Graph(int n) : n(n), m(0), g(n) {}
    /**
     * @brief 無向辺を追加する
     * @param u 始点
     * @param v 終点
     * @param w コスト 省略したら1
     */
    void add_edge(int u, int v, Cost w=1) {
        g[u].push_back({u, v, w, m});
        g[v].push_back({v, u, w, m++});
    }
    /**
     * @brief 有向辺を追加する
     * @param u 始点
     * @param v 終点
     * @param w コスト 省略したら1
     */
    void add_directed_edge(int u, int v, Cost w=1) {
        g[u].push_back({u, v, w, m++});
    }
    /**
     * @brief 辺の情報を標準入力から受け取って追加する
     * @param m 辺の数
     * @param padding 頂点番号を入力からいくつずらすか 省略したら-1
     * @param weighted 辺の重みが入力されるか 省略したらfalseとなり、重み1で辺が追加される
     * @param directed 有向グラフかどうか 省略したらfalse
     */
    void read(int m, int padding=-1, bool weighted=false, bool directed=false) {
        for(int i = 0; i < m; i++) {
            int u, v; std::cin >> u >> v; u += padding, v += padding;
            Cost c(1);
            if(weighted) std::cin >> c;
            if(directed) add_directed_edge(u, v, c);
            else add_edge(u, v, c);
        }
    }
    /**
     * @brief ある頂点から出る辺を列挙する
     * @param v 頂点番号
     * @return std::vector<Edge>& vから出る辺のリスト
     */
    std::vector<Edge>& operator[](int v) {
        return g[v];
    }
    /**
     * @brief ある頂点から出る辺を列挙する
     * @param v 頂点番号
     * @return const std::vector<Edge>& vから出る辺のリスト
     */
    const std::vector<Edge>& operator[](int v) const {
        return g[v];
    }
    /**
     * @brief 辺のリスト
     * @return std::vector<Edge> 辺のリスト(idの昇順)
     *
     * 無向辺は代表して1つだけ格納される
     */
    std::vector<Edge> edges() const {
        std::vector<Edge> res(m);
        for(int i = 0; i < n; i++) {
            for(auto& e : g[i]) {
                res[e.id] = e;
            }
        }
        return res;
    }
    /**
     * @brief ある頂点から各頂点への最短路
     *
     * @param s 始点
     * @param weighted 1以外のコストの辺が存在するか 省略するとtrue
     * @param inf コストのminの単位元 未到達の頂点への距離はinfになる 省略すると-1
     * @return std::pair<std::vector<Cost>, std::vector<Edge>> first:各頂点への最短路長 second:各頂点への最短路上の直前の辺
     */
    std::pair<std::vector<Cost>, std::vector<Edge>> shortest_path(int s, bool weignted = true, Cost inf = -1) const {
        if(weignted) return shortest_path_dijkstra(s, inf);
        return shortest_path_bfs(s, inf);
    }
    
    std::vector<int> topological_sort() {
        std::vector<int> indeg(n), sorted;
        std::queue<int> q;
        for (int i = 0; i < n; i++) {
            for (int dst : g[i]) indeg[dst]++;
        }
        for (int i = 0; i < n; i++) {
            if (!indeg[i]) q.push(i);
        }
        while (!q.empty()) {
            int cur = q.front(); q.pop();
            for (int dst : g[cur]) {
                if (!--indeg[dst]) q.push(dst);
            }
            sorted.push_back(cur);
        }
        return sorted;
    }

private:
    std::pair<std::vector<Cost>, std::vector<Edge>> shortest_path_bfs(int s, Cost inf) const {
        std::vector<Cost> dist(n, inf);
        std::vector<Edge> prev(n);
        std::queue<int> que;
        dist[s] = 0;
        que.push(s);
        while(!que.empty()) {
            int u = que.front(); que.pop();
            for(auto& e : g[u]) {
                if(dist[e.dst] == inf) {
                    dist[e.dst] = dist[e.src] + 1;
                    prev[e.dst] = e;
                    que.push(e.dst);
                }
            }
        }
        return {dist, prev};
    }
    std::pair<std::vector<Cost>, std::vector<Edge>> shortest_path_dijkstra(int s, Cost inf) const {
        std::vector<Cost> dist(n, inf);
        std::vector<Edge> prev(n);
        using Node = std::pair<Cost, int>;
        std::priority_queue<Node, std::vector<Node>, std::greater<Node>> que;
        dist[s] = 0;
        que.push({0, s});
        while(!que.empty()) {
            auto [d, u] = que.top(); que.pop();
            if(d > dist[u]) continue;
            for(auto& e : g[u]) {
                if(dist[e.dst] == inf || dist[e.dst] > dist[e.src] + e.cost) {
                    dist[e.dst] = dist[e.src] + e.cost;
                    prev[e.dst] = e;
                    que.push({dist[e.dst], e.dst});
                }
            }
        }
        return {dist, prev};
    }


};
#line 11 "/home/shogo314/cpp_include/ou-library/graph_util.hpp"

/**
 * @brief 無向グラフについて、二部グラフなら0と1に彩色した結果をひとつ返し、二部グラフでないなら空のvectorを返す。
 * 連結成分のうち、インデックスの最も小さいものを0にする。
 * @return std::vector<int> 各頂点の彩色結果
 */
template <typename Cost = int>
std::vector<int> bipartite_coloring(const Graph<Cost>& graph) {
    std::vector<int> color(graph.n, -1);
    for (int i = 0; i < graph.n; i++) {
        if (color[i] != -1) continue;
        std::stack<int> stk;
        stk.push(i);
        color[i] = 0;
        while (!stk.empty()) {
            int u = stk.top();
            stk.pop();
            for (int v : graph[u]) {
                if (color[v] == -1) {
                    color[v] = color[u] ^ 1;
                    stk.push(v);
                } else {
                    if (color[u] == color[v]) return {};
                }
            }
        }
    }
    return color;
}

/**
 * @brief 無向グラフについて、二部グラフかどうかを判定する。
 * @return bool 二部グラフならtrue、二部グラフでないならfalseを返す。
 */
template <typename Cost = int>
bool is_bipartite(const Graph<Cost>& graph) {
    return !bipartite_coloring(graph).empty();
}

/**
 * @brief 無向グラフについて、連結成分分解する。
 * @return std::vector<std::vector<int>> 「同じ連結成分となる頂点のリスト」のリスト
 */
template <typename Cost = int>
std::vector<std::vector<int>> connected_components(const Graph<Cost>& graph) {
    std::vector<std::vector<int>> groups;
    std::vector<bool> visited(graph.n);
    for (int i = 0; i < graph.n; i++) {
        if (visited[i]) continue;
        std::stack<int> stk;
        stk.push(i);
        visited[i] = true;
        groups.push_back({i});
        while (!stk.empty()) {
            int u = stk.top();
            stk.pop();
            for (int v : graph[u]) {
                if (visited[v]) continue;
                visited[v] = true;
                stk.push(v);
                groups.back().push_back(v);
            }
        }
    }
    return groups;
}

/**
 * @brief 無向グラフについて、連結グラフかどうかを判定する。
 * @return bool 連結グラフならtrue、連結グラフでないならfalseを返す。
 */
template <typename Cost = int>
bool is_connected(const Graph<Cost>& graph) {
    return connected_components(graph).size() == 1;
}

/**
 * @brief 無向グラフについて、木かどうかを判定する。
 * @return bool 木ならtrue、木でないならfalseを返す。
 */
template <typename Cost = int>
bool is_tree(const Graph<Cost>& graph) {
    return graph.m == graph.n - 1 && is_connected(graph);
}

/**
 * @brief 有向グラフをトポロジカルソートする
 * @param G トポロジカルソートするグラフ
 * @return ソートされたノード番号のvector DAGでなければ長さがG.n未満になる
 */
template<typename Cost>
std::vector<int> topological_sort(const Graph<Cost> &G) {
    std::vector<int> indeg(G.n), sorted;
    std::queue<int> q;
    for (int i = 0; i < G.n; i++) {
        for (int dst : G[i]) indeg[dst]++;
    }
    for (int i = 0; i < G.n; i++) {
        if (!indeg[i]) q.push(i);
    }
    while (!q.empty()) {
        int cur = q.front(); q.pop();
        for (int dst : G[cur]) {
            if (!--indeg[dst]) q.push(dst);
        }
        sorted.push_back(cur);
    }
    return sorted;
}
#line 2 "/home/shogo314/cpp_include/sh-library/base/all"
#include <bits/stdc++.h>
#line 5 "/home/shogo314/cpp_include/sh-library/base/container_func.hpp"
#include <initializer_list>
#line 3 "/home/shogo314/cpp_include/sh-library/base/traits.hpp"
#include <type_traits>

#define HAS_METHOD(func_name)                                                              \
    namespace detail {                                                                     \
    template <class T, class = void>                                                       \
    struct has_##func_name##_impl : std::false_type {};                                    \
    template <class T>                                                                     \
    struct has_##func_name##_impl<T, std::void_t<decltype(std::declval<T>().func_name())>> \
        : std::true_type {};                                                               \
    }                                                                                      \
    template <class T>                                                                     \
    struct has_##func_name : detail::has_##func_name##_impl<T>::type {};                   \
    template <class T>                                                                     \
    inline constexpr bool has_##func_name##_v = has_##func_name<T>::value;

#define HAS_METHOD_ARG(func_name)                                                                              \
    namespace detail {                                                                                         \
    template <class T, typename U, class = void>                                                               \
    struct has_##func_name##_impl : std::false_type {};                                                        \
    template <class T, typename U>                                                                             \
    struct has_##func_name##_impl<T, U, std::void_t<decltype(std::declval<T>().func_name(std::declval<U>()))>> \
        : std::true_type {};                                                                                   \
    }                                                                                                          \
    template <class T, typename U>                                                                             \
    struct has_##func_name : detail::has_##func_name##_impl<T, U>::type {};                                    \
    template <class T, typename U>                                                                             \
    inline constexpr bool has_##func_name##_v = has_##func_name<T, U>::value;

HAS_METHOD(repr)
HAS_METHOD(type_str)
HAS_METHOD(initializer_str)
HAS_METHOD(max)
HAS_METHOD(min)
HAS_METHOD(reversed)
HAS_METHOD(sorted)
HAS_METHOD(sum)
HAS_METHOD(product)
HAS_METHOD_ARG(count)
HAS_METHOD_ARG(find)
HAS_METHOD_ARG(lower_bound)
HAS_METHOD_ARG(upper_bound)

#define ENABLE_IF_T_IMPL(expr) std::enable_if_t<expr, std::nullptr_t> = nullptr
#define ENABLE_IF_T(...) ENABLE_IF_T_IMPL((__VA_ARGS__))

template <class C>
using mem_value_type = typename C::value_type;
template <class C>
using mem_difference_type = typename C::difference_type;
#line 9 "/home/shogo314/cpp_include/sh-library/base/container_func.hpp"

#define METHOD_EXPAND(func_name)                                             \
    template <typename T, ENABLE_IF_T(has_##func_name##_v<T>)>               \
    inline constexpr auto func_name(const T &t) -> decltype(t.func_name()) { \
        return t.func_name();                                                \
    }

#define METHOD_AND_FUNC_ARG_EXPAND(func_name)                                     \
    template <typename T, typename U, ENABLE_IF_T(has_##func_name##_v<T, U>)>     \
    inline constexpr auto func_name(const T &t, const U &u)                       \
        -> decltype(t.func_name(u)) {                                             \
        return t.func_name(u);                                                    \
    }                                                                             \
    template <typename T, typename U, ENABLE_IF_T(not has_##func_name##_v<T, U>)> \
    inline constexpr auto func_name(const T &t, const U &u)                       \
        -> decltype(func_name(t.begin(), t.end(), u)) {                           \
        using namespace std;                                                      \
        return func_name(t.begin(), t.end(), u);                                  \
    }

METHOD_EXPAND(reversed)
template <class C, ENABLE_IF_T(not has_reversed_v<C>)>
inline constexpr C reversed(C t) {
    std::reverse(t.begin(), t.end());
    return t;
}

METHOD_EXPAND(sorted)
template <class C, ENABLE_IF_T(not has_sorted_v<C>)>
inline constexpr C sorted(C t) {
    std::sort(t.begin(), t.end());
    return t;
}
template <class C, class F, ENABLE_IF_T(not has_sorted_v<C> and std::is_invocable_r_v<bool, F, mem_value_type<C>, mem_value_type<C>>)>
inline constexpr C sorted(C t, F f) {
    std::sort(t.begin(), t.end(), f);
    return t;
}

template <class C>
inline constexpr void sort(C &t) {
    std::sort(t.begin(), t.end());
}
template <class C, class F, ENABLE_IF_T(std::is_invocable_r_v<bool, F, mem_value_type<C>, mem_value_type<C>>)>
inline constexpr void sort(C &t, F f) {
    std::sort(t.begin(), t.end(), f);
}
template <class C, class F, ENABLE_IF_T(std::is_invocable_v<F, mem_value_type<C>>)>
inline constexpr void sort_by_key(C &t, F f) {
    std::sort(t.begin(), t.end(), [&](const mem_value_type<C> &left, const mem_value_type<C> &right) {
        return f(left) < f(right);
    });
}

template <class C>
inline constexpr void reverse(C &t) {
    std::reverse(t.begin(), t.end());
}

METHOD_EXPAND(max)
template <class C, ENABLE_IF_T(not has_max_v<C>)>
inline constexpr mem_value_type<C> max(const C &v) {
    assert(v.begin() != v.end());
    return *std::max_element(v.begin(), v.end());
}
template <typename T>
inline constexpr T max(const std::initializer_list<T> &v) {
    return std::max(v);
}

METHOD_EXPAND(min)
template <class C, ENABLE_IF_T(not has_max_v<C>)>
inline constexpr mem_value_type<C> min(const C &v) {
    assert(v.begin() != v.end());
    return *std::min_element(v.begin(), v.end());
}
template <typename T>
inline constexpr T min(const std::initializer_list<T> &v) {
    return std::min(v);
}

METHOD_EXPAND(sum)
template <class C, ENABLE_IF_T(not has_sum_v<C>)>
inline constexpr mem_value_type<C> sum(const C &v) {
    return std::accumulate(v.begin(), v.end(), mem_value_type<C>{});
}
template <typename T>
inline constexpr T sum(const std::initializer_list<T> &v) {
    return std::accumulate(v.begin(), v.end(), T{});
}

METHOD_EXPAND(product)
template <class C, ENABLE_IF_T(not has_product_v<C>)>
inline constexpr mem_value_type<C> product(const C &v) {
    return std::accumulate(v.begin(), v.end(), mem_value_type<C>{1}, std::multiplies<mem_value_type<C>>());
}
template <typename T>
inline constexpr T product(const std::initializer_list<T> &v) {
    return std::accumulate(v.begin(), v.end(), T{1}, std::multiplies<T>());
}

METHOD_AND_FUNC_ARG_EXPAND(count)
METHOD_AND_FUNC_ARG_EXPAND(find)
METHOD_AND_FUNC_ARG_EXPAND(lower_bound)
METHOD_AND_FUNC_ARG_EXPAND(upper_bound)

template <class C>
inline constexpr mem_value_type<C> gcd(const C &v) {
    mem_value_type<C> init(0);
    for (const auto &e : v) init = std::gcd(init, e);
    return init;
}

template <class C>
inline constexpr mem_value_type<C> average(const C &v) {
    assert(v.size());
    return sum(v) / v.size();
}

template <class C>
inline constexpr mem_value_type<C> median(const C &v) {
    assert(not v.empty());
    std::vector<size_t> u(v.size());
    std::iota(u.begin(), u.end(), 0);
    std::sort(u.begin(), u.end(), [&](size_t a, size_t b) {
        return v[a] < v[b];
    });
    if (v.size() & 1) {
        return v[u[v.size() / 2]];
    }
    // C++20
    // return std::midpoint(v[u[v.size() / 2]], v[u[v.size() / 2 - 1]]);
    return (v[u[v.size() / 2]] + v[u[v.size() / 2 - 1]]) / 2;
}

template <class C, typename U>
inline constexpr size_t index(const C &v, const U &x) {
    return std::distance(v.begin(), std::find(v.begin(), v.end(), x));
}

template <class C, ENABLE_IF_T(std::is_integral_v<mem_value_type<C>>)>
inline constexpr mem_value_type<C> mex(const C &v) {
    std::vector<bool> b(v.size() + 1);
    for (const auto &a : v) {
        if (0 <= a and a < b.size()) {
            b[a] = true;
        }
    }
    mem_value_type<C> ret;
    for (size_t i = 0; i < b.size(); i++) {
        if (not b[i]) {
            ret = i;
            break;
        }
    }
    return ret;
}

template <class C>
inline constexpr mem_difference_type<C> bisect_left(const C &v, const mem_value_type<C> &x) {
    return std::distance(v.begin(), lower_bound(v, x));
}
template <class C>
inline constexpr mem_difference_type<C> bisect_right(const C &v, const mem_value_type<C> &x) {
    return std::distance(v.begin(), upper_bound(v, x));
}
#line 6 "/home/shogo314/cpp_include/sh-library/base/functions.hpp"

template <typename T1, typename T2>
inline constexpr bool chmin(T1 &a, T2 b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

template <typename T1, typename T2>
inline constexpr bool chmax(T1 &a, T2 b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template <class C, typename T>
inline constexpr bool contains(const C &c, const T &t) {
    return c.find(t) != c.end();
}

inline constexpr long long max(const long long &t1, const long long &t2) {
    return std::max<long long>(t1, t2);
}

inline constexpr long long min(const long long &t1, const long long &t2) {
    return std::min<long long>(t1, t2);
}

using std::abs;
using std::gcd;
using std::lcm;
using std::size;

template <typename T>
constexpr T extgcd(const T &a, const T &b, T &x, T &y) {
    T d = a;
    if (b != 0) {
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    } else {
        x = 1;
        y = 0;
    }
    return d;
}

template <typename M, typename N, class F, ENABLE_IF_T(std::is_integral_v<std::common_type_t<M, N>> and std::is_invocable_r_v<bool, F, std::common_type_t<M, N>>)>
inline constexpr std::common_type_t<M, N> binary_search(const M &ok, const N &ng, F f) {
    std::common_type_t<M, N> _ok = ok, _ng = ng;
    assert(f(_ok));
    while (std::abs(_ok - _ng) > 1) {
        std::common_type_t<M, N> mid = (_ok + _ng) / 2;
        if (f(mid)) {
            _ok = mid;
        } else {
            _ng = mid;
        }
    }
    return _ok;
}

template <typename M, typename N, class F, ENABLE_IF_T(not std::is_integral_v<std::common_type_t<M, N>> and std::is_invocable_r_v<bool, F, std::common_type_t<M, N>>)>
inline constexpr std::common_type_t<M, N> binary_search(const M &ok, const N &ng, F f) {
    std::common_type_t<M, N> _ok = ok, _ng = ng;
    assert(f(_ok));
    for (int i = 0; i < 100; i++) {
        std::common_type_t<M, N> mid = (_ok + _ng) / 2;
        if (f(mid)) {
            _ok = mid;
        } else {
            _ng = mid;
        }
    }
    return _ok;
}
#line 8 "/home/shogo314/cpp_include/sh-library/base/io.hpp"

namespace tuple_io {
template <typename Tuple, size_t I, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& read_tuple(std::basic_istream<CharT, Traits>& is, Tuple& t) {
    is >> std::get<I>(t);
    if constexpr (I + 1 < std::tuple_size_v<Tuple>) {
        return read_tuple<Tuple, I + 1>(is, t);
    }
    return is;
}
template <typename Tuple, size_t I, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& write_tuple(std::basic_ostream<CharT, Traits>& os, const Tuple& t) {
    os << std::get<I>(t);
    if constexpr (I + 1 < std::tuple_size_v<Tuple>) {
        os << CharT(' ');
        return write_tuple<Tuple, I + 1>(os, t);
    }
    return os;
}
};  // namespace tuple_io

template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::pair<T1, T2>& p) {
    is >> p.first >> p.second;
    return is;
}
template <typename... Types, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::tuple<Types...>& p) {
    return tuple_io::read_tuple<std::tuple<Types...>, 0>(is, p);
}
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::array<T, N>& a) {
    for (auto& e : a) is >> e;
    return is;
}
template <typename T, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::vector<T>& v) {
    for (auto& e : v) is >> e;
    return is;
}

template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::pair<T1, T2>& p) {
    os << p.first << CharT(' ') << p.second;
    return os;
}
template <typename... Types, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::tuple<Types...>& p) {
    return tuple_io::write_tuple<std::tuple<Types...>, 0>(os, p);
}
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::array<T, N>& a) {
    for (size_t i = 0; i < N; ++i) {
        if (i) os << CharT(' ');
        os << a[i];
    }
    return os;
}
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::vector<T>& v) {
    for (size_t i = 0; i < v.size(); ++i) {
        if (i) os << CharT(' ');
        os << v[i];
    }
    return os;
}
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::set<T>& s) {
    for (auto itr = s.begin(); itr != s.end(); ++itr) {
        if (itr != s.begin()) os << CharT(' ');
        os << *itr;
    }
    return os;
}

/**
 * @brief 空行出力
 */
void print() { std::cout << '\n'; }
/**
 * @brief 出力して改行
 *
 * @tparam T 型
 * @param x 出力する値
 */
template <typename T>
void print(const T& x) { std::cout << x << '\n'; }
/**
 * @brief 空白区切りで出力して改行
 *
 * @tparam T 1つ目の要素の型
 * @tparam Tail 2つ目以降の要素の型
 * @param x 1つ目の要素
 * @param tail 2つ目以降の要素
 */
template <typename T, typename... Tail>
void print(const T& x, const Tail&... tail) {
    std::cout << x << ' ';
    print(tail...);
}

/**
 * @brief 空行出力
 */
void err() { std::cerr << std::endl; }
/**
 * @brief 出力して改行
 *
 * @tparam T 型
 * @param x 出力する値
 */
template <typename T>
void err(const T& x) { std::cerr << x << std::endl; }
/**
 * @brief 空白区切りで出力して改行
 *
 * @tparam T 1つ目の要素の型
 * @tparam Tail 2つ目以降の要素の型
 * @param x 1つ目の要素
 * @param tail 2つ目以降の要素
 */
template <typename T, typename... Tail>
void err(const T& x, const Tail&... tail) {
    std::cerr << x << ' ';
    err(tail...);
}
#line 3 "/home/shogo314/cpp_include/sh-library/base/type_alias.hpp"

using ll = long long;
using ull = unsigned long long;
using ld = long double;

template <typename T>
using vec = std::vector<T>;
template <typename T, int N>
using ary = std::array<T, N>;
using str = std::string;
using std::deque;
using std::list;
using std::map;
using std::pair;
using std::set;

using pl = pair<ll, ll>;
using pd = pair<ld, ld>;

template <typename T>
using vv = vec<vec<T>>;
template <typename T>
using vvv = vec<vec<vec<T>>>;
using vl = vec<ll>;
using vvl = vv<ll>;
using vvvl = vvv<ll>;
using vs = vec<str>;
using vc = vec<char>;
using vi = vec<int>;
using vb = vec<bool>;

template <typename T1, typename T2>
using vp = vec<pair<T1, T2>>;
using vpl = vec<pl>;
using vvpl = vv<pl>;
using vd = vec<ld>;
using vpd = vec<pd>;

template <int N>
using al = ary<ll, N>;
template <int N1, int N2>
using aal = ary<ary<ll, N2>, N1>;
template <int N>
using val = vec<al<N>>;

template <typename T>
using ml = std::map<ll, T>;
using mll = std::map<ll, ll>;
using sl = std::set<ll>;
using spl = set<pl>;
template <int N>
using sal = set<al<N>>;

template <typename T>
using heap_max = std::priority_queue<T, std::vector<T>, std::less<T>>;
template <typename T>
using heap_min = std::priority_queue<T, std::vector<T>, std::greater<T>>;
#line 3 "/home/shogo314/cpp_include/sh-library/base/macro.hpp"

#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define all(obj) (obj).begin(), (obj).end()

#define reps(i, a, n) for (long long i = (a); i < (n); i++)
#define rep(i, n) reps(i, 0, (n))
#define rrep(i, n) reps(i, 1, (n) + 1)
#define repds(i, a, n) for (long long i = (n)-1; i >= (a); i--)
#define repd(i, n) repds(i, 0, (n))
#define rrepd(i, n) repds(i, 1, (n) + 1)
#define rep2(i, j, x, y) rep(i, x) rep(j, y)

#define IN(a, x) a x; std::cin >> x;
#define CHAR(x) char x; std::cin >> x;
#define LL(x) ll x; std::cin >> x;
#define VL(a,n) vl a(n); std::cin >> a;
#define AL(a,k) al<k> a; std::cin >> a;
#define AAL(a,n,m) aal<n,m> a; std::cin >> a;
#define VC(a,n) vc a(n); std::cin >> a;
#define VS(a,n) vs a(n); std::cin >> a;
#define STR(s) str s; std::cin >> s;
#define VPL(a,n) vpl a(n); std::cin >> a;
#define VAL(a,n,k) val<k> a(n); std::cin >> a;
#define VVL(a,n,m) vvl a(n,vl(m)); std::cin >> a;
#define SL(a,n) sl a;{VL(b,n);a=sl(all(b));}
#line 8 "/home/shogo314/cpp_include/sh-library/base/vector_func.hpp"

template <typename T>
std::vector<std::ptrdiff_t> sorted_idx(const std::vector<T> &v) {
    std::vector<std::ptrdiff_t> ret(v.size());
    std::iota(ret.begin(), ret.end(), 0);
    std::sort(ret.begin(), ret.end(), [&](std::ptrdiff_t i, std::ptrdiff_t j) {
        return v[i] < v[j];
    });
    return ret;
}

template <typename T>
inline std::vector<T> &operator++(std::vector<T> &v) {
    for (auto &e : v) e++;
    return v;
}
template <typename T>
inline std::vector<T> operator++(std::vector<T> &v, int) {
    auto res = v;
    for (auto &e : v) e++;
    return res;
}
template <typename T>
inline std::vector<T> &operator--(std::vector<T> &v) {
    for (auto &e : v) e--;
    return v;
}
template <typename T>
inline std::vector<T> operator--(std::vector<T> &v, int) {
    auto res = v;
    for (auto &e : v) e--;
    return res;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator+=(std::vector<T> &v1, const std::vector<U> &v2) {
    if (v2.size() > v1.size()) {
        v1.resize(v2.size());
    }
    for (size_t i = 0; i < v2.size(); i++) {
        v1[i] += v2[i];
    }
    return v1;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator+(const std::vector<T> &v1, const std::vector<U> &v2) {
    std::vector<T> res(v1);
    return res += v2;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator+=(std::vector<T> &v, const U &u) {
    for (T &e : v) {
        e += u;
    }
    return v;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator+(const std::vector<T> &v, const U &u) {
    std::vector<T> res(v);
    return res += u;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator+(const U &u, const std::vector<T> &v) {
    std::vector<T> res(v);
    return res += u;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator*=(std::vector<T> &v1, const std::vector<U> &v2) {
    if (v2.size() > v1.size()) {
        v1.resize(v2.size());
    }
    for (size_t i = 0; i < v2.size(); i++) {
        v1[i] *= v2[i];
    }
    for (size_t i = v2.size(); i < v1.size(); i++) {
        v1[i] *= U(0);
    }
    return v1;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator*(const std::vector<T> &v1, const std::vector<U> &v2) {
    std::vector<T> res(v1);
    return res *= v2;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator*=(std::vector<T> &v, const U &u) {
    for (T &e : v) {
        e *= u;
    }
    return v;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator*(const std::vector<T> &v, const U &u) {
    std::vector<T> res(v);
    return res *= u;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator*(const U &u, const std::vector<T> &v) {
    std::vector<T> res(v);
    return res *= u;
}

template <typename T, typename U>
inline std::vector<T> &assign(std::vector<T> &v1, const std::vector<U> &v2) {
    v1.assign(v2.begin(), v2.end());
    return v1;
}

template <typename T, typename U>
inline std::vector<T> &extend(std::vector<T> &v1, const std::vector<U> &v2) {
    v1.insert(v1.end(), v2.begin(), v2.end());
    return v1;
}

template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator|=(std::vector<T> &v1, const std::vector<U> &v2) {
    return extend(v1, v2);
}

template <typename T, typename U, ENABLE_IF_T(std::is_integral_v<U>)>
inline std::vector<T> &operator|=(std::vector<T> &v, const U &u) {
    std::vector<T> w(v);
    v.clear();
    for (int i = 0; i < u; i++) {
        extend(v, w);
    }
    return v;
}

template <typename T, typename U, ENABLE_IF_T(std::is_integral_v<U>)>
inline std::vector<T> operator|(const std::vector<T> &v, const U &u) {
    std::vector<T> res(v);
    return res |= u;
}

template <typename T, typename U, ENABLE_IF_T(std::is_integral_v<U>)>
inline std::vector<T> operator|(const U &u, const std::vector<T> &v) {
    std::vector<T> res(v);
    return res |= u;
}

template <typename T>
inline std::vector<T> abs(const std::vector<T> &v) {
    std::vector<T> ret;
    ret.reserve(v.size());
    for (const T &e : v) ret.push_back(std::abs(e));
    return ret;
}

template <typename T>
std::vector<T> partial_sum(const std::vector<T> &v) {
    std::vector<T> ret(v.size());
    std::partial_sum(v.begin(), v.end(), ret.begin());
    return ret;
}
#line 3 "main.cpp"

void solve() {
    LL(N);
    LL(M);
    LL(S);
    LL(T);
    S--, T--;
    LL(K);
    Graph<ll> g(N);
    g.read(M);
    auto cc = connected_components(g);
    vl connected_coloring(N);
    rep(i, cc.size()) {
        for (ll x : cc[i]) {
            connected_coloring[x] = i;
        }
    }
    if (connected_coloring[S] != connected_coloring[T]) {
        if (N == 2 and K % 2 == 0) {
            print("No");
        } else {
            print("Unknown");
        }
        return;
    }
    auto bc = bipartite_coloring(g);
    if (K % 2 != (bc[S] + bc[T]) % 2) {
        print("No");
    } else {
        ll dist = g.shortest_path(S, false).first[T];
        if (dist <= K) {
            assert(false);
            print("Yes");
        } else {
            print("Unknown");
        }
    }
}

int main() {
    std::cin.tie(nullptr);
    std::ios_base::sync_with_stdio(false);
    solve();
}
0