#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <iostream>
#include <string>
#include <vector>

struct Clause {
    int start = 0;
    int size = 0;
    int w0 = 0;
    int w1 = 0;
};

static inline int lit_index(int lit) {
    int v = std::abs(lit);
    return (v << 1) ^ (lit < 0);
}

static inline int neg_lit_index(int idx) {
    return idx ^ 1;
}

static inline int lit_from_index(int idx) {
    int v = idx >> 1;
    return (idx & 1) ? -v : v;
}

struct CNF {
    int nvars = 0;
    int nclauses = 0;
    std::vector<int> lits;
    std::vector<Clause> clauses;
    std::vector<std::vector<int>> watch;
    std::vector<signed char> val;
    std::deque<int> queue;

    int lit_val(int lit) const {
        signed char x = val[std::abs(lit)];
        if (x == 0) return 0;
        return (lit > 0) ? x : -x;
    }

    bool assign(int lit) {
        int v = std::abs(lit);
        signed char want = lit > 0 ? 1 : -1;
        if (val[v] == want) return true;
        if (val[v] == -want) return false;
        val[v] = want;
        queue.push_back(lit);
        return true;
    }

    bool parse_dimacs(FILE* f) {
        char ch;
        while ((ch = std::getc(f)) != EOF) {
            if (ch == 'c') {
                while ((ch = std::getc(f)) != EOF && ch != '\n') {}
            } else if (ch == 'p') {
                char buf[16];
                if (std::fscanf(f, "%15s %d %d", buf, &nvars, &nclauses) != 3) return false;
                break;
            }
        }
        if (nvars <= 0 || nclauses < 0) return false;
        clauses.reserve(nclauses);
        lits.reserve((size_t)nclauses * 3);
        std::vector<int> cur;
        cur.reserve(8);
        int x;
        while (std::fscanf(f, "%d", &x) == 1) {
            if (x == 0) {
                Clause c;
                c.start = (int)lits.size();
                c.size = (int)cur.size();
                c.w0 = 0;
                c.w1 = cur.size() > 1 ? 1 : 0;
                for (int lit : cur) lits.push_back(lit);
                clauses.push_back(c);
                cur.clear();
            } else {
                cur.push_back(x);
            }
        }
        val.assign(nvars + 1, 0);
        watch.assign((nvars + 1) * 2, {});
        for (int cid = 0; cid < (int)clauses.size(); ++cid) {
            Clause& c = clauses[cid];
            if (c.size == 0) return false;
            if (c.size == 1) {
                if (!assign(lits[c.start])) return false;
            } else {
                watch[lit_index(lits[c.start + c.w0])].push_back(cid);
                watch[lit_index(lits[c.start + c.w1])].push_back(cid);
            }
        }
        return true;
    }

    bool propagate() {
        while (!queue.empty()) {
            int lit = queue.front();
            queue.pop_front();
            int false_idx = lit_index(-lit);
            auto& ws = watch[false_idx];
            size_t out = 0;
            for (size_t p = 0; p < ws.size(); ++p) {
                int cid = ws[p];
                Clause& c = clauses[cid];
                int base = c.start;
                int wi_false;
                int wi_other;
                if (lit_index(lits[base + c.w0]) == false_idx) {
                    wi_false = c.w0;
                    wi_other = c.w1;
                } else {
                    wi_false = c.w1;
                    wi_other = c.w0;
                }
                int other_lit = lits[base + wi_other];
                if (lit_val(other_lit) == 1) {
                    ws[out++] = cid;
                    continue;
                }
                bool moved = false;
                for (int i = 0; i < c.size; ++i) {
                    if (i == c.w0 || i == c.w1) continue;
                    int cand = lits[base + i];
                    if (lit_val(cand) != -1) {
                        if (wi_false == c.w0) c.w0 = i; else c.w1 = i;
                        watch[lit_index(cand)].push_back(cid);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                ws[out++] = cid;
                int ov = lit_val(other_lit);
                if (ov == -1) {
                    ws.resize(out);
                    return false;
                }
                if (ov == 0 && !assign(other_lit)) {
                    ws.resize(out);
                    return false;
                }
            }
            ws.resize(out);
        }
        return true;
    }

    long long count_unsat_clauses() const {
        long long bad = 0;
        for (const Clause& c : clauses) {
            bool sat = false;
            for (int i = 0; i < c.size; ++i) {
                if (lit_val(lits[c.start + i]) == 1) {
                    sat = true;
                    break;
                }
            }
            if (!sat) ++bad;
        }
        return bad;
    }
};

int main(int argc, char** argv) {
    if (argc < 2) {
        std::fprintf(stderr, "usage: bcp_stats formula.cnf [vars...]\n");
        return 2;
    }
    FILE* f = std::fopen(argv[1], "r");
    if (!f) {
        std::perror(argv[1]);
        return 2;
    }
    CNF cnf;
    if (!cnf.parse_dimacs(f)) {
        std::fprintf(stderr, "parse or initial assignment conflict\n");
        return 1;
    }
    std::fclose(f);
    bool ok = cnf.propagate();
    int assigned = 0, t = 0, ff = 0;
    for (int v = 1; v <= cnf.nvars; ++v) {
        if (cnf.val[v]) {
            ++assigned;
            if (cnf.val[v] > 0) ++t; else ++ff;
        }
    }
    std::cout << "ok=" << ok << " vars=" << cnf.nvars << " clauses=" << cnf.clauses.size()
              << " assigned=" << assigned << " true=" << t << " false=" << ff << "\n";
    std::cout << "unsatisfied_or_unresolved_clauses_if_unassigned_false=" << cnf.count_unsat_clauses() << "\n";
    for (int i = 2; i < argc; ++i) {
        int v = std::atoi(argv[i]);
        if (v >= 1 && v <= cnf.nvars) {
            std::cout << "val[" << v << "]=" << (int)cnf.val[v] << "\n";
        }
    }
    return ok ? 0 : 20;
}
