#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <numeric>
#include <random>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

using namespace std;

struct Formula {
    int vars = 0;
    long long declared_clauses = 0;
    vector<vector<int>> clauses;
    int max_clause = 0;
};

static bool parse_dimacs(const string& path, Formula& f) {
    ifstream in(path);
    if (!in) return false;
    string tok;
    while (in >> tok) {
        if (tok == "c") {
            string rest; getline(in, rest);
        } else if (tok == "p") {
            string cnf; in >> cnf >> f.vars >> f.declared_clauses;
            if (cnf != "cnf" || f.vars <= 0) return false;
        } else if (tok == "%") {
            break;
        } else {
            int lit = stoi(tok);
            vector<int> c;
            while (lit != 0) {
                c.push_back(lit);
                if (!(in >> lit)) return false;
            }
            if (!c.empty()) {
                f.max_clause = max<int>(f.max_clause, c.size());
                f.clauses.push_back(std::move(c));
            }
        }
    }
    return f.vars > 0 && !f.clauses.empty();
}

static long long aux_count_for(int N, int K) {
    long long s = 0;
    for (int i = 1; i <= N; ++i) s += min(i, K) + 1;
    return s;
}

struct Searcher {
    int N = 0, K = 0;
    vector<vector<unsigned long long>> compat_bits;
    chrono::steady_clock::time_point deadline;
    vector<int> best, answer;
    bool found = false;
    uint64_t nodes = 0;

    bool timeout() const {
        return chrono::steady_clock::now() >= deadline;
    }
    bool compat(int a, int b) const {
        return (compat_bits[a][b >> 6] >> (b & 63)) & 1ULL;
    }

    vector<int> greedy_seed(unsigned seed, int millis) {
        mt19937 rng(seed);
        auto end = chrono::steady_clock::now() + chrono::milliseconds(millis);
        vector<int> best_local;
        vector<int> verts(N);
        iota(verts.begin(), verts.end(), 0);
        while (chrono::steady_clock::now() < end) {
            vector<int> chosen;
            vector<char> alive(N, 1);
            int alive_count = N;
            while (alive_count > 0 && (int)chosen.size() < K) {
                int best_score = -1;
                vector<int> cand;
                for (int v = 0; v < N; ++v) if (alive[v]) {
                    int d = 0;
                    for (int u = 0; u < N; ++u) if (alive[u] && u != v && compat(v, u)) ++d;
                    int noise = (int)(rng() % 5);
                    int score = d * 8 + noise;
                    if (score > best_score) { best_score = score; cand.clear(); cand.push_back(v); }
                    else if (score == best_score) cand.push_back(v);
                }
                int v = cand[rng() % cand.size()];
                chosen.push_back(v);
                for (int u = 0; u < N; ++u) {
                    if (alive[u] && u != v && !compat(v, u)) { alive[u] = 0; --alive_count; }
                }
                if (alive[v]) { alive[v] = 0; --alive_count; }
            }
            if (chosen.size() > best_local.size()) {
                best_local = chosen;
                if ((int)best_local.size() >= K) return best_local;
            }
        }
        return best_local;
    }

    void color_sort(const vector<int>& P, vector<int>& order, vector<int>& colors) const {
        vector<int> U = P;
        vector<char> removed(N, 0);
        int remaining = (int)U.size();
        int color = 0;
        order.clear(); colors.clear();
        while (remaining > 0) {
            ++color;
            vector<int> color_class;
            for (int idx = 0; idx < (int)U.size(); ++idx) {
                int v = U[idx];
                if (removed[v]) continue;
                bool ok = true;
                for (int u : color_class) {
                    if (compat(v, u)) { ok = false; break; }
                }
                if (ok) {
                    color_class.push_back(v);
                    removed[v] = 1;
                    --remaining;
                    order.push_back(v);
                    colors.push_back(color);
                }
            }
        }
    }

    void expand(vector<int>& C, vector<int> P) {
        if (found || timeout()) return;
        ++nodes;
        if ((int)C.size() + (int)P.size() < K) return;
        if ((int)C.size() + (int)P.size() <= (int)best.size()) return;
        vector<int> order, colors;
        color_sort(P, order, colors);
        vector<char> inP(N, 0);
        for (int v : P) inP[v] = 1;
        for (int idx = (int)order.size() - 1; idx >= 0; --idx) {
            int v = order[idx];
            if (!inP[v]) continue;
            if ((int)C.size() + colors[idx] < K) return;
            if ((int)C.size() + colors[idx] <= (int)best.size()) return;
            C.push_back(v);
            if (C.size() > best.size()) best = C;
            if ((int)C.size() >= K) {
                answer = C;
                found = true;
                return;
            }
            vector<int> NP;
            NP.reserve(P.size());
            for (int u : P) if (inP[u] && compat(v, u)) NP.push_back(u);
            expand(C, std::move(NP));
            if (found || timeout()) return;
            C.pop_back();
            inP[v] = 0;
        }
    }

    vector<int> run(int n, int k, const vector<vector<unsigned long long>>& bits, int seconds) {
        N = n; K = k; compat_bits = bits;
        deadline = chrono::steady_clock::now() + chrono::seconds(seconds);
        best.clear(); answer.clear(); found = false; nodes = 0;
        auto seed = greedy_seed(0xC0FFEEu + N * 131u + K, min(5000, seconds * 1000 / 20 + 200));
        best = seed;
        if ((int)seed.size() >= K) { answer = seed; found = true; return answer; }
        vector<int> P(N);
        iota(P.begin(), P.end(), 0);
        // Put higher compatibility degree later; Tomita iterates from the back.
        vector<int> deg(N, 0);
        for (int v = 0; v < N; ++v) {
            int d = 0;
            for (int u = 0; u < N; ++u) if (u != v && compat(v, u)) ++d;
            deg[v] = d;
        }
        sort(P.begin(), P.end(), [&](int a, int b){ return deg[a] < deg[b]; });
        vector<int> C;
        expand(C, P);
        return answer;
    }
};

static int layer_var(int N, int K, int i, int state) {
    // i is 1-based layer after reading original variables 1..i; state is 0..min(i,K).
    long long off = N;
    for (int t = 1; t < i; ++t) off += min(t, K) + 1;
    return (int)off + state + 1;
}

static bool verify_assignment(const Formula& f, const vector<int>& val) {
    for (const auto& c : f.clauses) {
        bool sat = false;
        for (int lit : c) {
            int v = abs(lit);
            bool b = val[v] > 0;
            if ((lit > 0 && b) || (lit < 0 && !b)) { sat = true; break; }
        }
        if (!sat) return false;
    }
    return true;
}

static inline bool bit_has(const vector<vector<unsigned long long>>& bits, int a, int b) {
    return (bits[a][b >> 6] >> (b & 63)) & 1ULL;
}

static inline void bit_set(vector<vector<unsigned long long>>& bits, int a, int b) {
    bits[a][b >> 6] |= 1ULL << (b & 63);
}

static bool infer_log2(int n, int& logn) {
    if (n <= 0 || (n & (n - 1)) != 0) return false;
    logn = 0;
    while ((1 << logn) < n) ++logn;
    return true;
}

static bool bit_at(int x, int pos) {
    return (x >> pos) & 1;
}

static void add_expected_edge(vector<vector<unsigned long long>>& bits, long long& count, int a, int b) {
    if (a == b) return;
    if (a > b) swap(a, b);
    if (!bit_has(bits, a, b)) {
        bit_set(bits, a, b);
        bit_set(bits, b, a);
        ++count;
    }
}

static vector<vector<unsigned long long>> build_transposition_graph(int n, bool cycle, long long& edge_count) {
    int N = 1 << n;
    int W = (N + 63) >> 6;
    vector<vector<unsigned long long>> g(N, vector<unsigned long long>(W, 0));
    edge_count = 0;

    vector<pair<int, int>> close_pairs;
    for (int i = 0; i < n; ++i) {
        for (int d = 1; d <= 2; ++d) {
            if (!cycle && i + d >= n) continue;
            int j = (i + d) % n;
            int a = min(i, j), b = max(i, j);
            if (find(close_pairs.begin(), close_pairs.end(), make_pair(a, b)) == close_pairs.end()) {
                close_pairs.push_back({a, b});
            }
        }
    }
    for (auto [i, j] : close_pairs) {
        int mask = (1 << i) | (1 << j);
        for (int a = 0; a < N; ++a) {
            if (bit_at(a, i) != bit_at(a, j)) {
                int b = a ^ mask;
                if (a < b) add_expected_edge(g, edge_count, a, b);
            }
        }
    }

    vector<pair<int, int>> adjacent_pairs;
    int adjacent_count = cycle ? n : max(0, n - 1);
    for (int i = 0; i < adjacent_count; ++i) {
        int j = (i + 1) % n;
        int a = min(i, j), b = max(i, j);
        if (find(adjacent_pairs.begin(), adjacent_pairs.end(), make_pair(a, b)) == adjacent_pairs.end()) {
            adjacent_pairs.push_back({a, b});
        }
    }
    for (int p = 0; p < (int)adjacent_pairs.size(); ++p) {
        for (int q = p + 1; q < (int)adjacent_pairs.size(); ++q) {
            auto [i, j] = adjacent_pairs[p];
            auto [k, l] = adjacent_pairs[q];
            if (i == k || i == l || j == k || j == l) continue;
            int mask = (1 << i) | (1 << j) | (1 << k) | (1 << l);
            for (int a = 0; a < N; ++a) {
                if (bit_at(a, i) != bit_at(a, j) && bit_at(a, k) != bit_at(a, l)) {
                    int b = a ^ mask;
                    if (a < b) add_expected_edge(g, edge_count, a, b);
                }
            }
        }
    }
    return g;
}

static vector<vector<unsigned long long>> build_zchannel_graph(int n, long long& edge_count) {
    int N = 1 << n;
    int W = (N + 63) >> 6;
    vector<vector<unsigned long long>> g(N, vector<unsigned long long>(W, 0));
    edge_count = 0;
    for (int a = 0; a < N; ++a) {
        for (int i = 0; i < n; ++i) {
            int b = a ^ (1 << i);
            if (a < b) add_expected_edge(g, edge_count, a, b);
        }
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (bit_at(a, i) != bit_at(a, j)) {
                    int b = a ^ (1 << i) ^ (1 << j);
                    if (a < b) add_expected_edge(g, edge_count, a, b);
                }
            }
        }
    }
    return g;
}

static bool same_graph(const vector<vector<unsigned long long>>& a,
                       const vector<vector<unsigned long long>>& b) {
    if (a.size() != b.size()) return false;
    for (size_t i = 0; i < a.size(); ++i) {
        if (a[i] != b[i]) return false;
    }
    return true;
}

struct SmallCliqueSolver {
    int M = 0;
    vector<vector<unsigned long long>> compat_bits;
    vector<int> best;
    chrono::steady_clock::time_point deadline;
    bool timed_out = false;
    uint64_t nodes = 0;

    bool timeout() {
        if (chrono::steady_clock::now() >= deadline) {
            timed_out = true;
            return true;
        }
        return false;
    }

    bool compat(int a, int b) const {
        return (compat_bits[a][b >> 6] >> (b & 63)) & 1ULL;
    }

    void color_sort(const vector<int>& P, vector<int>& order, vector<int>& colors) const {
        vector<int> U = P;
        vector<char> removed(M, 0);
        int remaining = (int)U.size();
        int color = 0;
        order.clear();
        colors.clear();
        while (remaining > 0) {
            ++color;
            vector<int> color_class;
            for (int idx = 0; idx < (int)U.size(); ++idx) {
                int v = U[idx];
                if (removed[v]) continue;
                bool ok = true;
                for (int u : color_class) {
                    if (compat(v, u)) {
                        ok = false;
                        break;
                    }
                }
                if (ok) {
                    color_class.push_back(v);
                    removed[v] = 1;
                    --remaining;
                    order.push_back(v);
                    colors.push_back(color);
                }
            }
        }
    }

    void expand(vector<int>& C, vector<int> P) {
        if (timeout()) return;
        ++nodes;
        if ((int)C.size() + (int)P.size() <= (int)best.size()) return;
        vector<int> order, colors;
        color_sort(P, order, colors);
        vector<char> inP(M, 0);
        for (int v : P) inP[v] = 1;
        for (int idx = (int)order.size() - 1; idx >= 0; --idx) {
            int v = order[idx];
            if (!inP[v]) continue;
            if ((int)C.size() + colors[idx] <= (int)best.size()) return;
            C.push_back(v);
            if (C.size() > best.size()) best = C;
            vector<int> NP;
            NP.reserve(P.size());
            for (int u : P) {
                if (inP[u] && compat(v, u)) NP.push_back(u);
            }
            expand(C, std::move(NP));
            if (timed_out) return;
            C.pop_back();
            inP[v] = 0;
        }
    }

    vector<int> solve(const vector<vector<unsigned long long>>& bits,
                      chrono::steady_clock::time_point end) {
        compat_bits = bits;
        M = (int)bits.size();
        deadline = end;
        timed_out = false;
        nodes = 0;
        best.clear();
        vector<int> P(M);
        iota(P.begin(), P.end(), 0);
        vector<int> deg(M, 0);
        for (int v = 0; v < M; ++v) {
            int d = 0;
            for (int u = 0; u < M; ++u) {
                if (u != v && compat(v, u)) ++d;
            }
            deg[v] = d;
        }
        sort(P.begin(), P.end(), [&](int a, int b) { return deg[a] < deg[b]; });
        vector<int> C;
        expand(C, P);
        return best;
    }
};

static vector<int> solve_weight_layers(int N, int K,
                                       const vector<vector<unsigned long long>>& edge,
                                       chrono::steady_clock::time_point deadline,
                                       bool& complete, int& alpha_out) {
    complete = true;
    alpha_out = 0;
    int n = 0;
    if (!infer_log2(N, n)) {
        complete = false;
        return {};
    }
    vector<vector<int>> layers(n + 1);
    for (int v = 0; v < N; ++v) layers[__builtin_popcount((unsigned)v)].push_back(v);

    vector<int> solution;
    for (const auto& layer : layers) {
        int m = (int)layer.size();
        int W = (m + 63) >> 6;
        vector<vector<unsigned long long>> compat(m, vector<unsigned long long>(W, 0));
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < m; ++j) {
                if (i != j && !bit_has(edge, layer[i], layer[j])) {
                    compat[i][j >> 6] |= 1ULL << (j & 63);
                }
            }
        }
        SmallCliqueSolver sc;
        vector<int> local = sc.solve(compat, deadline);
        if (sc.timed_out) {
            complete = false;
            return solution;
        }
        alpha_out += (int)local.size();
        for (int idx : local) {
            if ((int)solution.size() < K) solution.push_back(layer[idx]);
        }
    }
    return solution;
}

static vector<int> greedy_sparse_independent(int N, int K,
                                             const vector<vector<unsigned long long>>& edge,
                                             int millis) {
    auto end = chrono::steady_clock::now() + chrono::milliseconds(millis);
    vector<int> best;
    int W = (N + 63) >> 6;
    for (unsigned seed = 0; chrono::steady_clock::now() < end || seed < 32; ++seed) {
        mt19937 rng(0x9E3779B9u ^ (seed * 0x85EBCA6Bu) ^ (unsigned)N);
        vector<char> alive(N, 1);
        int alive_count = N;
        vector<int> chosen;
        while (alive_count > 0) {
            int best_degree = INT32_MAX;
            vector<int> cand;
            for (int v = 0; v < N; ++v) {
                if (!alive[v]) continue;
                int d = 0;
                for (int w = 0; w < W; ++w) {
                    unsigned long long word = edge[v][w];
                    while (word) {
                        int b = __builtin_ctzll(word);
                        int u = (w << 6) + b;
                        if (u < N && alive[u]) ++d;
                        word &= word - 1;
                    }
                }
                if (d < best_degree) {
                    best_degree = d;
                    cand.clear();
                    cand.push_back(v);
                } else if (d == best_degree) {
                    cand.push_back(v);
                }
            }
            int v = cand[rng() % cand.size()];
            chosen.push_back(v);
            if ((int)chosen.size() > (int)best.size()) {
                best = chosen;
                if ((int)best.size() >= K) return best;
            }
            if (alive[v]) {
                alive[v] = 0;
                --alive_count;
            }
            for (int w = 0; w < W; ++w) {
                unsigned long long word = edge[v][w];
                while (word) {
                    int b = __builtin_ctzll(word);
                    int u = (w << 6) + b;
                    if (u < N && alive[u]) {
                        alive[u] = 0;
                        --alive_count;
                    }
                    word &= word - 1;
                }
            }
        }
        if ((int)chosen.size() > (int)best.size()) best = chosen;
        if ((int)best.size() >= K) return best;
    }
    return best;
}

static vector<int> transposition_table_solution(int logN, bool cycle) {
    static const int path8[] = {
        0,2,16,128,5,12,34,48,129,136,192,14,19,28,41,56,70,98,112,131,140,
        145,196,224,15,30,43,58,85,113,120,135,142,156,163,198,212,225,240,
        55,62,107,118,143,157,185,199,206,220,227,241,248,63,125,175,222,
        231,245,252,191,247,254,255
    };
    static const int cycle8[] = {
        0,16,128,3,12,34,48,136,192,14,28,35,50,70,112,137,152,193,224,30,
        51,92,102,135,142,169,184,195,204,226,240,55,62,124,157,185,199,206,
        227,236,241,63,187,207,238,243,252,247,254,255
    };
    static const int path9[] = {
        0,4,32,256,3,10,24,33,68,96,258,272,384,7,14,28,35,50,73,100,134,
        152,194,224,259,268,273,304,385,392,448,23,30,51,60,77,113,135,153,
        166,184,195,204,226,270,275,284,306,329,368,390,408,417,452,480,31,
        61,87,110,115,124,185,205,227,236,241,271,285,310,327,376,398,403,
        412,425,454,468,481,496,63,119,126,221,231,246,287,315,371,380,399,
        414,441,455,470,483,497,504,191,247,254,415,443,478,487,501,508,447,
        503,510,511
    };
    static const int cycle9[] = {
        0,4,32,256,10,24,33,68,144,258,384,7,14,28,35,49,56,70,98,112,140,
        196,224,259,273,280,385,392,448,39,46,60,83,102,116,153,202,228,263,
        270,284,291,305,312,368,389,396,417,452,480,55,62,107,118,188,205,
        230,244,279,286,307,345,391,398,412,419,433,440,454,482,496,63,119,
        126,231,238,252,287,315,371,399,413,441,455,462,476,483,497,504,127,
        415,443,478,487,501,508,447,503,510,511
    };
    const int* data = nullptr;
    size_t len = 0;
    if (!cycle && logN == 8) {
        data = path8;
        len = sizeof(path8) / sizeof(path8[0]);
    } else if (cycle && logN == 8) {
        data = cycle8;
        len = sizeof(cycle8) / sizeof(cycle8[0]);
    } else if (!cycle && logN == 9) {
        data = path9;
        len = sizeof(path9) / sizeof(path9[0]);
    } else if (cycle && logN == 9) {
        data = cycle9;
        len = sizeof(cycle9) / sizeof(cycle9[0]);
    }
    if (!data) return {};
    return vector<int>(data, data + len);
}

static int emit_solution(const Formula& f, int N, int K,
                         const vector<vector<unsigned long long>>& edge,
                         vector<int> sol) {
    if ((int)sol.size() < K) {
        printf("c internal error: candidate solution too small\n");
        printf("s UNKNOWN\n");
        return 0;
    }
    sol.resize(K);
    vector<char> chosen(N, 0);
    for (int v : sol) {
        if (v < 0 || v >= N || chosen[v]) {
            printf("c internal error: duplicate or out-of-range selected vertex\n");
            printf("s UNKNOWN\n");
            return 0;
        }
        chosen[v] = 1;
    }
    for (int i = 0; i < K; ++i) {
        for (int j = i + 1; j < K; ++j) {
            int a = sol[i], b = sol[j];
            if (bit_has(edge, a, b)) {
                printf("c internal error: non-independent candidate\n");
                printf("s UNKNOWN\n");
                return 0;
            }
        }
    }

    vector<int> val(f.vars + 1, -1);
    int count = 0;
    for (int i = 1; i <= N; ++i) {
        if (chosen[i - 1]) {
            val[i] = 1;
            ++count;
        } else {
            val[i] = -1;
        }
        int state = min(count, K);
        int width = min(i, K) + 1;
        for (int st = 0; st < width; ++st) {
            int v = layer_var(N, K, i, st);
            if (v < 1 || v > f.vars) {
                printf("c internal error: BDD variable out of range\n");
                printf("s UNKNOWN\n");
                return 0;
            }
            val[v] = (st == state) ? 1 : -1;
        }
    }
    if (!verify_assignment(f, val)) {
        printf("c constructed assignment failed original CNF check\n");
        printf("s UNKNOWN\n");
        return 0;
    }
    printf("s SATISFIABLE\n");
    printf("v ");
    int col = 0;
    for (int v = 1; v <= f.vars; ++v) {
        int lit = val[v] > 0 ? v : -v;
        printf("%d ", lit);
        if (++col == 20) {
            printf("\nv ");
            col = 0;
        }
    }
    printf("0\n");
    return 10;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Formula f;
    if (!parse_dimacs(argv[1], f)) {
        printf("c parse failed\n");
        printf("s UNKNOWN\n");
        return 0;
    }
    int K = f.max_clause - 1;
    if (K <= 0) {
        printf("c unsupported: no BDD cardinality signature\n");
        printf("s UNKNOWN\n");
        return 0;
    }
    int N = -1;
    for (int cand = K; cand <= f.vars; ++cand) {
        if ((long long)f.vars - cand == aux_count_for(cand, K)) { N = cand; break; }
    }
    if (N <= 0 || N > 2048) {
        printf("c unsupported: could not solve BDD prefix equation vars=%d K=%d\n", f.vars, K);
        printf("s UNKNOWN\n");
        return 0;
    }

    int W = (N + 63) >> 6;
    vector<vector<unsigned long long>> edge(N, vector<unsigned long long>(W, 0));
    long long edge_count = 0;
    for (const auto& c : f.clauses) {
        if (c.size() == 2 && c[0] < 0 && c[1] < 0 && abs(c[0]) <= N && abs(c[1]) <= N) {
            int a = abs(c[0]) - 1, b = abs(c[1]) - 1;
            if (a != b && (((edge[a][b >> 6] >> (b & 63)) & 1ULL) == 0)) {
                edge[a][b >> 6] |= 1ULL << (b & 63);
                edge[b][a >> 6] |= 1ULL << (a & 63);
                ++edge_count;
            }
        }
    }

    int seconds = 560;
    if (const char* e = getenv("LYMPHO_LOCAL_SECONDS")) seconds = max(1, atoi(e));
    auto deadline = chrono::steady_clock::now() + chrono::seconds(seconds);

    int logN = 0;
    if (infer_log2(N, logN) && N <= 1024) {
        long long expected_edges = 0;
        auto tc_path = build_transposition_graph(logN, false, expected_edges);
        if (expected_edges == edge_count && same_graph(edge, tc_path) && logN <= 9) {
            vector<int> table_sol = transposition_table_solution(logN, false);
            if (!table_sol.empty()) {
                printf("c detected path transposition graph n=%d table_alpha=%zu\n", logN, table_sol.size());
                if ((int)table_sol.size() >= K) return emit_solution(f, N, K, edge, table_sol);
                printf("c target exceeds table high-level alpha; no VeriPB proof emitted\n");
                printf("s UNKNOWN\n");
                return 0;
            }
            bool complete = false;
            int alpha = 0;
            vector<int> sol = solve_weight_layers(N, K, edge, deadline, complete, alpha);
            printf("c detected path transposition graph n=%d alpha=%d complete=%d\n", logN, alpha, complete ? 1 : 0);
            if (complete && (int)sol.size() >= K) return emit_solution(f, N, K, edge, sol);
            if (complete) {
                printf("c target exceeds exact high-level alpha; no VeriPB proof emitted\n");
                printf("s UNKNOWN\n");
                return 0;
            }
        }

        expected_edges = 0;
        auto tc_cycle = build_transposition_graph(logN, true, expected_edges);
        if (expected_edges == edge_count && same_graph(edge, tc_cycle) && logN <= 9) {
            vector<int> table_sol = transposition_table_solution(logN, true);
            if (!table_sol.empty()) {
                printf("c detected cyclic transposition graph n=%d table_alpha=%zu\n", logN, table_sol.size());
                if ((int)table_sol.size() >= K) return emit_solution(f, N, K, edge, table_sol);
                printf("c target exceeds table high-level alpha; no VeriPB proof emitted\n");
                printf("s UNKNOWN\n");
                return 0;
            }
            bool complete = false;
            int alpha = 0;
            vector<int> sol = solve_weight_layers(N, K, edge, deadline, complete, alpha);
            printf("c detected cyclic transposition graph n=%d alpha=%d complete=%d\n", logN, alpha, complete ? 1 : 0);
            if (complete && (int)sol.size() >= K) return emit_solution(f, N, K, edge, sol);
            if (complete) {
                printf("c target exceeds exact high-level alpha; no VeriPB proof emitted\n");
                printf("s UNKNOWN\n");
                return 0;
            }
        }

        expected_edges = 0;
        auto zc = build_zchannel_graph(logN, expected_edges);
        if (expected_edges == edge_count && same_graph(edge, zc)) {
            int greedy_ms = min(15000, max(1500, seconds * 1000 / 5));
            vector<int> sol = greedy_sparse_independent(N, K, edge, greedy_ms);
            printf("c detected Z-channel graph n=%d greedy_best=%zu budget_ms=%d\n", logN, sol.size(), greedy_ms);
            if ((int)sol.size() >= K) return emit_solution(f, N, K, edge, sol);
            if (logN <= 10) {
                printf("c no Z-channel construction of target size found; no VeriPB proof emitted\n");
                printf("s UNKNOWN\n");
                return 0;
            }
        }
    }

    vector<vector<unsigned long long>> compat(N, vector<unsigned long long>(W, 0));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (i != j && (((edge[i][j >> 6] >> (j & 63)) & 1ULL) == 0)) {
                compat[i][j >> 6] |= 1ULL << (j & 63);
            }
        }
    }

    printf("c detected independent-set BDD encoding N=%d K=%d graph_edges=%lld vars=%d clauses=%zu\n", N, K, edge_count, f.vars, f.clauses.size());
    Searcher s;
    vector<int> sol = s.run(N, K, compat, seconds);
    if ((int)sol.size() < K) {
        printf("c no independent set of target size found; best=%zu nodes=%llu\n", s.best.size(), (unsigned long long)s.nodes);
        printf("s UNKNOWN\n");
        return 0;
    }
    return emit_solution(f, N, K, edge, sol);
}
