#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <numeric>
#include <random>
#include <string>
#include <utility>
#include <vector>

using Clock = std::chrono::steady_clock;

struct Formula {
    int vars = 0;
    int clauses = 0;
    std::vector<int> starts;
    std::vector<int> lits;
};

static bool read_file(const char* path, std::string& out) {
    FILE* f = std::fopen(path, "rb");
    if (!f) return false;
    std::fseek(f, 0, SEEK_END);
    long sz = std::ftell(f);
    std::fseek(f, 0, SEEK_SET);
    if (sz < 0) { std::fclose(f); return false; }
    out.resize((size_t)sz);
    size_t got = std::fread(out.data(), 1, out.size(), f);
    std::fclose(f);
    return got == out.size();
}

static bool parse_dimacs(const char* path, Formula& F) {
    std::string s;
    if (!read_file(path, s)) return false;
    const char* p = s.data();
    const char* e = p + s.size();
    F.starts.clear();
    F.lits.clear();
    std::vector<int> cur;
    while (p < e) {
        while (p < e && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p;
        if (p >= e) break;
        if (*p == 'c') {
            while (p < e && *p != '\n') ++p;
            continue;
        }
        if (*p == 'p') {
            while (p < e && *p != ' ') ++p;
            while (p < e && *p == ' ') ++p;
            while (p < e && *p != ' ') ++p; // cnf
            while (p < e && *p == ' ') ++p;
            F.vars = (int)std::strtol(p, (char**)&p, 10);
            while (p < e && *p == ' ') ++p;
            F.clauses = (int)std::strtol(p, (char**)&p, 10);
            F.starts.reserve((size_t)F.clauses + 1);
            F.lits.reserve((size_t)F.clauses * 3);
            continue;
        }
        int lit = (int)std::strtol(p, (char**)&p, 10);
        if (lit == 0) {
            F.starts.push_back((int)F.lits.size());
            F.lits.insert(F.lits.end(), cur.begin(), cur.end());
            cur.clear();
        } else {
            cur.push_back(lit);
        }
    }
    F.starts.push_back((int)F.lits.size());
    return F.vars > 0 && (int)F.starts.size() == F.clauses + 1;
}

struct BitGraph {
    int n = 0;
    int B = 0;
    std::vector<std::vector<uint64_t>> adj;
};

static inline void set_bit(std::vector<uint64_t>& b, int i) { b[i >> 6] |= 1ULL << (i & 63); }
static inline void clear_bit(std::vector<uint64_t>& b, int i) { b[i >> 6] &= ~(1ULL << (i & 63)); }
static inline bool has_bit(const std::vector<uint64_t>& b, int i) { return (b[i >> 6] >> (i & 63)) & 1ULL; }
static inline int popcnt64(uint64_t x) { return (int)__builtin_popcountll(x); }

static int bit_degree(const std::vector<uint64_t>& a, const std::vector<uint64_t>& rem) {
    int r = 0;
    for (size_t i = 0; i < a.size(); ++i) r += popcnt64(a[i] & rem[i]);
    return r;
}

static bool intersects(const std::vector<uint64_t>& a, const std::vector<uint64_t>& b) {
    for (size_t i = 0; i < a.size(); ++i) if (a[i] & b[i]) return true;
    return false;
}

static std::vector<int> bits_to_list(const std::vector<uint64_t>& a, const std::vector<uint64_t>& rem, int n) {
    std::vector<int> xs;
    for (int block = 0; block < (int)a.size(); ++block) {
        uint64_t x = a[block] & rem[block];
        while (x) {
            int bit = __builtin_ctzll(x);
            int v = (block << 6) + bit;
            if (v < n) xs.push_back(v);
            x &= x - 1;
        }
    }
    return xs;
}

static int fill_count(const BitGraph& g, const std::vector<int>& neigh) {
    int fill = 0;
    for (int i = 0; i < (int)neigh.size(); ++i) {
        const auto& ai = g.adj[neigh[i]];
        for (int j = i + 1; j < (int)neigh.size(); ++j) {
            if (!has_bit(ai, neigh[j])) ++fill;
        }
    }
    return fill;
}

static bool is_clique_neigh(const BitGraph& g, const std::vector<int>& neigh) {
    for (int i = 0; i < (int)neigh.size(); ++i) {
        const auto& ai = g.adj[neigh[i]];
        for (int j = i + 1; j < (int)neigh.size(); ++j) {
            if (!has_bit(ai, neigh[j])) return false;
        }
    }
    return true;
}

static bool is_almost_clique_neigh(const BitGraph& g, const std::vector<int>& neigh) {
    int d = (int)neigh.size();
    if (d <= 2) return true;
    for (int skip = 0; skip < d; ++skip) {
        bool ok = true;
        for (int i = 0; i < d && ok; ++i) if (i != skip) {
            const auto& ai = g.adj[neigh[i]];
            for (int j = i + 1; j < d; ++j) if (j != skip) {
                if (!has_bit(ai, neigh[j])) { ok = false; break; }
            }
        }
        if (ok) return true;
    }
    return false;
}

static void clique_fill(BitGraph& g, const std::vector<int>& neigh) {
    for (int i = 0; i < (int)neigh.size(); ++i) {
        int u = neigh[i];
        for (int j = i + 1; j < (int)neigh.size(); ++j) {
            int v = neigh[j];
            set_bit(g.adj[u], v);
            set_bit(g.adj[v], u);
        }
    }
}

struct Candidate {
    int width = 1000000000;
    std::vector<int> order; // 0-based vertices in elimination order
};

struct Choice {
    long long key = 0;
    int fill = 0;
    int deg = 0;
    int v = -1;
    std::vector<int> neigh;
};

static Candidate greedy_order(
    const BitGraph& base,
    const std::vector<std::vector<uint64_t>>& pred,
    int mode,
    int cap,
    int topk,
    std::mt19937_64& rng
) {
    BitGraph g = base;
    std::vector<uint64_t> rem(g.B, ~0ULL);
    if ((g.n & 63) != 0) rem.back() &= (1ULL << (g.n & 63)) - 1ULL;
    Candidate c;
    c.width = 0;
    c.order.reserve(g.n);
    std::uniform_int_distribution<int> dummy(0, 0);

    for (int step = 0; step < g.n; ++step) {
        std::vector<Choice> choices;
        choices.reserve(g.n);
        for (int v = 0; v < g.n; ++v) {
            if (!has_bit(rem, v)) continue;
            if (intersects(pred[v], rem)) continue;
            auto neigh = bits_to_list(g.adj[v], rem, g.n);
            int deg = (int)neigh.size();
            if (cap >= 0 && deg > cap) continue;
            int fill = fill_count(g, neigh);
            long long key;
            switch (mode) {
                case 1: key = (long long)deg * 1000000LL + fill; break;
                case 2: key = (long long)(4 * fill + deg) * 1000000LL + fill * 1000LL + deg; break;
                case 3: key = (long long)(2 * fill + deg) * 1000000LL + fill * 1000LL + deg; break;
                case 4: key = (long long)(fill - deg) * 1000000LL + fill * 1000LL + deg; break;
                case 5: key = (long long)(-deg) * 1000000LL + fill * 1000LL + v; break;
                case 6: key = (long long)(fill) * 1000000LL - deg * 1000LL + v; break;
                default: key = (long long)fill * 1000000LL + deg; break;
            }
            choices.push_back({key, fill, deg, v, std::move(neigh)});
        }
        if (choices.empty()) {
            c.width = 1000000000;
            c.order.clear();
            return c;
        }
        std::sort(choices.begin(), choices.end(), [](const Choice& a, const Choice& b) {
            if (a.key != b.key) return a.key < b.key;
            return a.v < b.v;
        });
        int pick = 0;
        if (topk == 0) {
            std::uniform_int_distribution<int> dist(0, (int)choices.size() - 1);
            pick = dist(rng);
        } else if (topk < 0) {
            if (topk == -2) {
                int lim = std::max<int>(1, (int)choices.size() / 2);
                std::uniform_int_distribution<int> dist(0, lim - 1);
                pick = dist(rng);
            } else if (topk == -3) {
                std::uniform_real_distribution<double> dist(0.0, 1.0);
                double r = dist(rng);
                pick = std::min<int>((int)choices.size() - 1, (int)(r * r * choices.size()));
            } else {
                long double total = 0.0L;
                std::vector<long double> weights(choices.size());
                for (size_t i = 0; i < choices.size(); ++i) {
                    weights[i] = 1.0L / ((long double)(choices[i].fill + 1) * (long double)(choices[i].deg + 1));
                    total += weights[i];
                }
                std::uniform_real_distribution<long double> dist(0.0L, total);
                long double r = dist(rng), acc = 0.0L;
                for (int i = 0; i < (int)weights.size(); ++i) {
                    acc += weights[i];
                    if (acc >= r) { pick = i; break; }
                }
            }
        } else if (topk > 1) {
            int lim = std::min<int>(topk, choices.size());
            std::uniform_int_distribution<int> dist(0, lim - 1);
            pick = dist(rng);
        }
        Choice ch = std::move(choices[pick]);
        c.width = std::max(c.width, ch.deg);
        clique_fill(g, ch.neigh);
        clear_bit(rem, ch.v);
        c.order.push_back(ch.v);
    }
    return c;
}

struct SearchStats {
    uint64_t nodes = 0;
    uint64_t limit = 0;
    Clock::time_point deadline;
};

static bool bounded_dfs_rec(
    const std::vector<std::vector<uint64_t>>& pred,
    int target,
    int mode,
    BitGraph& g,
    std::vector<uint64_t>& rem,
    std::vector<int>& prefix,
    std::vector<int>& result,
    SearchStats& st
) {
    int entry_prefix = (int)prefix.size();
    auto fail = [&]() {
        prefix.resize(entry_prefix);
        return false;
    };
    if (Clock::now() >= st.deadline || st.nodes++ >= st.limit) return fail();
    while (true) {
        if ((int)prefix.size() == g.n) {
            result = prefix;
            return true;
        }
        int best_v = -1;
        std::vector<int> best_neigh;
        int best_deg = 1000000000;
        int best_kind = 3;
        for (int v = 0; v < g.n; ++v) {
            if (!has_bit(rem, v)) continue;
            if (intersects(pred[v], rem)) continue;
            auto neigh = bits_to_list(g.adj[v], rem, g.n);
            int deg = (int)neigh.size();
            if (deg > target) continue;
            int kind = 3;
            if (is_clique_neigh(g, neigh)) kind = 0;
            else if (is_almost_clique_neigh(g, neigh)) kind = 1;
            if (kind < best_kind || (kind == best_kind && deg < best_deg)) {
                best_kind = kind;
                best_deg = deg;
                best_v = v;
                best_neigh = std::move(neigh);
            }
        }
        if (best_v < 0 || best_kind > 1) break;
        clique_fill(g, best_neigh);
        clear_bit(rem, best_v);
        prefix.push_back(best_v);
    }
    if ((int)prefix.size() == g.n) {
        result = prefix;
        return true;
    }

    std::vector<Choice> choices;
    choices.reserve(g.n);
    int min_deg = 1000000000;
    for (int v = 0; v < g.n; ++v) {
        if (!has_bit(rem, v)) continue;
        if (intersects(pred[v], rem)) continue;
        auto neigh = bits_to_list(g.adj[v], rem, g.n);
        int deg = (int)neigh.size();
        min_deg = std::min(min_deg, deg);
        if (deg > target) continue;
        int fill = fill_count(g, neigh);
        long long key;
        switch (mode) {
            case 1: key = (long long)deg * 1000000LL + fill * 1000LL + v; break;
            case 2: key = (long long)(-deg) * 1000000LL + fill * 1000LL + v; break;
            case 3: key = (long long)(2 * fill + deg) * 1000000LL + fill * 1000LL + v; break;
            case 4: key = (long long)(fill - deg) * 1000000LL + fill * 1000LL + v; break;
            default: key = (long long)fill * 1000000LL + deg * 1000LL + v; break;
        }
        choices.push_back({key, fill, deg, v, std::move(neigh)});
    }
    if (choices.empty()) return fail();
    if (min_deg > target) return fail();

    std::sort(choices.begin(), choices.end(), [](const Choice& a, const Choice& b) {
        if (a.key != b.key) return a.key < b.key;
        return a.v < b.v;
    });

    int branch_cap = g.n <= 90 ? 64 : (g.n <= 140 ? 28 : 14);
    if ((int)choices.size() > branch_cap) choices.resize(branch_cap);

    for (const Choice& ch : choices) {
        BitGraph ng = g;
        std::vector<uint64_t> nrem = rem;
        clique_fill(ng, ch.neigh);
        clear_bit(nrem, ch.v);
        prefix.push_back(ch.v);
        int child_entry = (int)prefix.size();
        if (bounded_dfs_rec(pred, target, mode, ng, nrem, prefix, result, st)) return true;
        prefix.resize(child_entry - 1);
    }
    return fail();
}

static Candidate bounded_search(const BitGraph& base, const std::vector<std::vector<uint64_t>>& pred, int target, int mode, uint64_t node_limit, Clock::time_point deadline) {
    Candidate c;
    c.width = 1000000000;
    c.order.clear();
    BitGraph g = base;
    std::vector<uint64_t> rem(g.B, ~0ULL);
    if ((g.n & 63) != 0) rem.back() &= (1ULL << (g.n & 63)) - 1ULL;
    std::vector<int> prefix, result;
    prefix.reserve(g.n);
    SearchStats st;
    st.limit = node_limit;
    st.deadline = deadline;
    if (bounded_dfs_rec(pred, target, mode, g, rem, prefix, result, st)) {
        c.width = target;
        c.order = std::move(result);
    }
    return c;
}

struct Encoding {
    int n = 0;
    int order_end = 0;
    int arc_start = 0;
    int arc_end = 0;
    std::vector<std::pair<int,int>> edges;      // 0-based
    std::vector<std::pair<int,int>> precedence; // 0-based a before b
};

static int order_var(int n, int i, int j) { // 0-based, i < j
    return 2 + i * n - (i * (i + 1)) / 2 + (j - i - 1);
}

static int arc_var(const Encoding& E, int i, int j) {
    return E.arc_start + i * E.n + j;
}

static std::pair<int,int> decode_order_var(int n, int var) {
    int x = var - 2;
    for (int i = 0; i < n - 1; ++i) {
        int row = n - i - 1;
        if (x < row) return {i, i + 1 + x};
        x -= row;
    }
    return {-1, -1};
}

static std::pair<int,int> decode_arc_var(const Encoding& E, int var) {
    int off = var - E.arc_start;
    return {off / E.n, off % E.n};
}

static bool detect_clean_encoding(const Formula& F, Encoding& E) {
    if (F.clauses <= 0 || F.starts.size() < 2) return false;
    int s = F.starts[0], t = F.starts[1];
    if (t - s != 3) return false;
    int a = F.lits[s], b = F.lits[s + 1], c = F.lits[s + 2];
    if (a != -2 || c != 3 || b >= 0) return false;
    E.n = -b - 1;
    if (E.n < 3 || E.n > 10000) return false;
    E.order_end = 1 + E.n * (E.n - 1) / 2;
    E.arc_start = E.order_end + 1;
    E.arc_end = E.arc_start + E.n * E.n - 1;
    if (E.arc_end > F.vars) return false;

    std::vector<uint8_t> edge_seen((size_t)E.n * E.n, 0);
    std::vector<uint8_t> prec_seen((size_t)E.n * E.n, 0);
    for (int ci = 0; ci < F.clauses; ++ci) {
        int cs = F.starts[ci], ce = F.starts[ci + 1];
        int len = ce - cs;
        if (len == 2) {
            int l1 = F.lits[cs], l2 = F.lits[cs + 1];
            if (l1 > 0 && l2 > 0 && l1 >= E.arc_start && l1 <= E.arc_end && l2 >= E.arc_start && l2 <= E.arc_end) {
                auto p = decode_arc_var(E, l1);
                auto q = decode_arc_var(E, l2);
                if (p.first == q.second && p.second == q.first && p.first != p.second) {
                    int u = std::min(p.first, p.second), v = std::max(p.first, p.second);
                    size_t idx = (size_t)u * E.n + v;
                    if (!edge_seen[idx]) {
                        edge_seen[idx] = 1;
                        E.edges.push_back({u, v});
                    }
                }
            }
        } else if (len == 1) {
            int lit = F.lits[cs];
            int v = std::abs(lit);
            if (v >= 2 && v <= E.order_end) {
                auto p = decode_order_var(E.n, v);
                if (p.first >= 0) {
                    int before = lit > 0 ? p.first : p.second;
                    int after = lit > 0 ? p.second : p.first;
                    size_t idx = (size_t)before * E.n + after;
                    if (!prec_seen[idx]) {
                        prec_seen[idx] = 1;
                        E.precedence.push_back({before, after});
                    }
                }
            }
        }
    }
    return !E.edges.empty();
}

static BitGraph build_graph(const Encoding& E) {
    BitGraph g;
    g.n = E.n;
    g.B = (E.n + 63) >> 6;
    g.adj.assign(E.n, std::vector<uint64_t>(g.B, 0));
    for (auto [u, v] : E.edges) {
        set_bit(g.adj[u], v);
        set_bit(g.adj[v], u);
    }
    return g;
}

static std::vector<std::vector<uint64_t>> build_pred(const Encoding& E) {
    int B = (E.n + 63) >> 6;
    std::vector<std::vector<uint64_t>> pred(E.n, std::vector<uint64_t>(B, 0));
    for (auto [a, b] : E.precedence) {
        if (a != b) set_bit(pred[b], a);
    }
    // Transitive closure for availability checks. n is small.
    bool changed = true;
    while (changed) {
        changed = false;
        for (int v = 0; v < E.n; ++v) {
            std::vector<uint64_t> add = pred[v];
            for (int u = 0; u < E.n; ++u) {
                if (has_bit(pred[v], u)) {
                    for (int b = 0; b < B; ++b) add[b] |= pred[u][b];
                }
            }
            for (int b = 0; b < B; ++b) {
                uint64_t old = pred[v][b];
                pred[v][b] |= add[b];
                if (pred[v][b] != old) changed = true;
            }
            if (has_bit(pred[v], v)) {
                // Cycle; mark impossible by making every vertex depend on itself.
                for (int x = 0; x < E.n; ++x) set_bit(pred[x], x);
                return pred;
            }
        }
    }
    return pred;
}

static Candidate find_candidate(const Encoding& E) {
    BitGraph g = build_graph(E);
    auto pred = build_pred(E);
    Candidate best;
    std::mt19937_64 rng(0x5eed12345678ULL);

    for (int mode = 0; mode < 7; ++mode) {
        Candidate c = greedy_order(g, pred, mode, -1, 1, rng);
        if (!c.order.empty() && c.width < best.width) best = std::move(c);
    }

    auto deadline = Clock::now() + std::chrono::seconds(180);
    int rounds = E.n <= 80 ? 2500 : 700;
    for (int r = 0; r < rounds && Clock::now() < deadline; ++r) {
        int mode = r % 7;
        int topk = 2 + (r % 11);
        Candidate c = greedy_order(g, pred, mode, -1, topk, rng);
        if (!c.order.empty() && c.width < best.width) best = std::move(c);
    }

    return best;
}

static Candidate improve_candidate(const Encoding& E, int width) {
    BitGraph g = build_graph(E);
    auto pred = build_pred(E);
    std::mt19937_64 rng(0x9e3779b97f4a7c15ULL ^ (uint64_t)width);
    auto deadline = Clock::now() + std::chrono::seconds(45);
    Candidate best;
    best.width = width;
    for (int target = width - 1; target >= 0 && target >= width - 8 && Clock::now() < deadline; --target) {
        bool improved = false;
        int tries = E.n <= 100 ? 400000 : (E.n <= 160 ? 90000 : 45000);
        for (int r = 0; r < tries && Clock::now() < deadline; ++r) {
            int mode = r % 7;
            int pat = r % 9;
            int topk;
            if (pat == 0) topk = 0;
            else if (pat == 1) topk = -1;
            else if (pat == 2) topk = -2;
            else if (pat == 3) topk = -3;
            else topk = 2 + (r % 23);
            Candidate c = greedy_order(g, pred, mode, target, topk, rng);
            if (!c.order.empty()) {
                best = std::move(c);
                improved = true;
                break;
            }
        }
        if (!improved && E.n <= 100 && Clock::now() < deadline) {
            BitGraph exact_base = build_graph(E);
            auto exact_pred = build_pred(E);
            uint64_t nodes = E.n <= 70 ? 8000000ULL : 5000000ULL;
            for (int mode = 0; mode < 5 && Clock::now() < deadline; ++mode) {
                Candidate c = bounded_search(exact_base, exact_pred, target, mode, nodes, deadline);
                if (!c.order.empty()) {
                    best = std::move(c);
                    improved = true;
                    break;
                }
            }
        }
        if (!improved) break;
    }
    return best.order.empty() ? Candidate{} : best;
}

static void assign_order_and_arcs(const Encoding& E, const Candidate& C, std::vector<int8_t>& asg) {
    asg.assign((size_t)0, 0);
    asg.resize((size_t)E.arc_end + 1, -1);
    std::vector<int> pos(E.n);
    for (int i = 0; i < E.n; ++i) pos[C.order[i]] = i;

    if ((int)asg.size() <= E.arc_end) asg.resize((size_t)E.arc_end + 1, -1);
    for (int i = 0; i < E.n; ++i) {
        for (int j = i + 1; j < E.n; ++j) {
            int v = order_var(E.n, i, j);
            asg[v] = pos[i] < pos[j] ? 1 : -1;
        }
    }
    for (int v = E.arc_start; v <= E.arc_end; ++v) asg[v] = -1;

    BitGraph g = build_graph(E);
    std::vector<uint64_t> rem(g.B, ~0ULL);
    if ((g.n & 63) != 0) rem.back() &= (1ULL << (g.n & 63)) - 1ULL;
    for (int step = 0; step < E.n; ++step) {
        int v = C.order[step];
        auto neigh = bits_to_list(g.adj[v], rem, E.n);
        for (int u : neigh) {
            asg[arc_var(E, v, u)] = 1;
        }
        clique_fill(g, neigh);
        clear_bit(rem, v);
    }
}

static bool lit_true(int lit, const std::vector<int8_t>& asg) {
    int v = std::abs(lit);
    int8_t a = v < (int)asg.size() ? asg[v] : 0;
    return (lit > 0 && a == 1) || (lit < 0 && a == -1);
}

static bool lit_false(int lit, const std::vector<int8_t>& asg) {
    int v = std::abs(lit);
    int8_t a = v < (int)asg.size() ? asg[v] : 0;
    return (lit > 0 && a == -1) || (lit < 0 && a == 1);
}

static bool set_lit_true(int lit, std::vector<int8_t>& asg) {
    int v = std::abs(lit);
    if (v >= (int)asg.size()) asg.resize((size_t)v + 1, 0);
    int8_t val = lit > 0 ? 1 : -1;
    if (asg[v] == 0) {
        asg[v] = val;
        return true;
    }
    return asg[v] == val;
}

static bool unit_propagate_and_complete(const Formula& F, std::vector<int8_t>& asg, bool debug=false) {
    if ((int)asg.size() <= F.vars) asg.resize((size_t)F.vars + 1, 0);
    bool changed = true;
    int passes = 0;
    while (changed && passes < 200) {
        changed = false;
        ++passes;
        for (int ci = 0; ci < F.clauses; ++ci) {
            int cs = F.starts[ci], ce = F.starts[ci + 1];
            bool sat = false;
            int un = 0, last = 0;
            for (int p = cs; p < ce; ++p) {
                int lit = F.lits[p];
                if (lit_true(lit, asg)) { sat = true; break; }
                if (!lit_false(lit, asg)) { ++un; last = lit; }
            }
            if (sat) continue;
            if (un == 0) {
                if (debug) {
                    std::fprintf(stderr, "conflict clause %d:", ci + 1);
                    for (int p = cs; p < ce; ++p) std::fprintf(stderr, " %d", F.lits[p]);
                    std::fprintf(stderr, "\n");
                }
                return false;
            }
            if (un == 1) {
                int v = std::abs(last);
                int8_t old = asg[v];
                if (!set_lit_true(last, asg)) return false;
                if (old == 0) changed = true;
            }
        }
    }
    if (changed) return false;
    for (int v = 1; v <= F.vars; ++v) if (asg[v] == 0) asg[v] = -1;
    return true;
}

static bool verify_formula(const Formula& F, const std::vector<int8_t>& asg) {
    for (int ci = 0; ci < F.clauses; ++ci) {
        int cs = F.starts[ci], ce = F.starts[ci + 1];
        bool sat = false;
        for (int p = cs; p < ce; ++p) {
            if (lit_true(F.lits[p], asg)) { sat = true; break; }
        }
        if (!sat) return false;
    }
    return true;
}

static void print_model(const std::vector<int8_t>& asg, int vars) {
    std::printf("s SATISFIABLE\n");
    const int per = 12;
    for (int i = 1; i <= vars; i += per) {
        std::printf("v");
        int end = std::min(vars, i + per - 1);
        for (int v = i; v <= end; ++v) {
            int lit = asg[v] == 1 ? v : -v;
            std::printf(" %d", lit);
        }
        if (end == vars) std::printf(" 0");
        std::printf("\n");
    }
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }

    Formula F;
    if (!parse_dimacs(argv[1], F)) {
        std::printf("s UNKNOWN\n");
        return 0;
    }

    Encoding E;
    if (!detect_clean_encoding(F, E)) {
        std::printf("s UNKNOWN\n");
        return 0;
    }
    bool debug = std::getenv("LYMPHOSAT_DEBUG") != nullptr;
    if (debug) std::fprintf(stderr, "detected n=%d edges=%zu precedence=%zu vars=%d clauses=%d\n", E.n, E.edges.size(), E.precedence.size(), F.vars, F.clauses);

    Candidate C = find_candidate(E);
    if (C.order.empty()) {
        std::printf("s UNKNOWN\n");
        return 0;
    }
    for (int attempt = 0; attempt < 3; ++attempt) {
        if (debug) std::fprintf(stderr, "candidate width=%d\n", C.width);
        std::vector<int8_t> asg;
        assign_order_and_arcs(E, C, asg);
        if (unit_propagate_and_complete(F, asg, debug) && verify_formula(F, asg)) {
            print_model(asg, F.vars);
            return 10;
        }
        if (debug) std::fprintf(stderr, "candidate failed\n");
        Candidate next = improve_candidate(E, C.width);
        if (next.order.empty() || next.width >= C.width) break;
        C = std::move(next);
    }

    std::printf("s UNKNOWN\n");
    return 0;
}
