#include #include #include #include #include #include #define lsb(x) ((x) & -(x)) using uint = unsigned int; bool solve() { int n, m; std::cin >> n >> m; const int k = std::bit_width(uint(n)) - 1; // such that 2^k = n if (n != 1 << k) return false; std::vector> adj(n); for (int i = 0; i < m; i++) { int a, b; std::cin >> a >> b; a--, b--; adj[a].insert(b); adj[b].insert(a); } for (const auto &vs : adj) if (vs.size() != k) return false; std::vector< int> addressToNode(n); std::vector nodeToAddress(n, -1); { addressToNode[0] = 0; nodeToAddress[0] = 0; int i = 0; for (const int v : adj[0]) { addressToNode[1 << i] = v; nodeToAddress[v] = 1 << i; i++; } } // we want to assign each address to a vertex // consider e.g. A := 00111010 // then 00111000 and 00110010 are already assigned (since they're smaller) // these should have exactly two common neighbors: A and B := 00110000 // again, B is already assigned, so exactly one common neighboring node must be free // we assign A to that node for (uint a = 0b11; a < n; a++) { if (std::popcount(a) >= 2) { const uint a1 = a ^ lsb(a); const uint a2 = a ^ lsb(a1); const int u1 = addressToNode[a1]; const int u2 = addressToNode[a2]; std::vector common; for (const int v : adj[u1]) if (adj[u2].contains(v)) common.push_back(v); // the following implements the above reasoning exhaustively assert(!common.empty()); if (common.size() != 2) return false; int v1 = common[0]; int v2 = common[1]; if (nodeToAddress[v1] == -1) if (nodeToAddress[v2] == -1) return false; else std::swap(v1, v2); else if (nodeToAddress[v2] == -1) ; else return false; addressToNode[a] = v2; nodeToAddress[v2] = a; } } for (int u = 0; u < n; u++) for (const int v : adj[u]) if (std::popcount(nodeToAddress[u] ^ nodeToAddress[v]) != 1) return false; return true; } int main() { std::cin.tie(0)->sync_with_stdio(0); std::cout << (solve() ? "yes" : "no") << std::endl; }