#include <bits/stdc++.h>
using namespace std;

struct CNF{int n=0,m=0; vector<vector<int>> c;};
static CNF read_cnf(const string& path){FILE*f=fopen(path.c_str(),"r"); if(!f){perror(path.c_str()); exit(2);} CNF cnf; char buf[1<<20]; vector<int> cur; while(fgets(buf,sizeof(buf),f)){ if(buf[0]=='c'||buf[0]=='\n') continue; if(buf[0]=='p'){char s[16]; sscanf(buf,"p %15s %d %d",s,&cnf.n,&cnf.m); continue;} char*p=buf; while(*p){while(*p&&isspace((unsigned char)*p))++p; if(!*p)break; char*e; long x=strtol(p,&e,10); p=e; if(x==0){ if(!cur.empty()){cnf.c.push_back(cur); cur.clear();}} else cur.push_back((int)x);} } if(!cur.empty()) cnf.c.push_back(cur); fclose(f); return cnf;}
static long long C3(long long x){return x*(x-1)*(x-2)/6;}
static bool gate3(const vector<vector<int>>&c,int i,int&a,int&b,int&d){ if(i+2>=(int)c.size())return false; auto&x=c[i];auto&y=c[i+1];auto&z=c[i+2]; if(x.size()!=3||y.size()!=3||z.size()!=3)return false; a=-x[0];b=-x[1];d=x[2]; return a>0&&b>0&&d>0&&y[0]==-a&&y[1]==b&&y[2]==-d&&z[0]==a&&z[1]==-b&&z[2]==-d; }
struct PM{int M=0,P=0,gc=0; vector<pair<int,int>> vp; vector<vector<int>> pv;};
static PM infer(const CNF&cnf){int gc=0,a,b,d; while(gate3(cnf.c,gc*3,a,b,d))++gc; int M=0; for(int x=3;x<1000;x++) if(C3(x)==gc){M=x;break;} if(!M)return{}; int P=M*(M-1)/2; PM pm; pm.M=M;pm.P=P;pm.gc=gc;pm.vp.assign(P+1,{-1,-1});pm.pv.assign(M,vector<int>(M)); auto setp=[&](int v,int i,int j){if(i>j)swap(i,j); pm.vp[v]={i,j}; pm.pv[i][j]=pm.pv[j][i]=v;}; setp(1,0,1); vector<int> y0(M); y0[1]=1; for(int off=0;off<M-2;off++){gate3(cnf.c,off*3,a,b,d); int j=off+2; y0[j]=b; setp(b,0,j); setp(d,1,j);} vector<int> idx(P+1,-1); for(int i=1;i<M;i++) idx[y0[i]]=i; for(int gi=0;gi<gc;gi++){gate3(cnf.c,gi*3,a,b,d); if(a<=P&&b<=P&&idx[a]>=0&&idx[b]>=0&&idx[a]<idx[b]&&!pm.pv[idx[a]][idx[b]]) setp(d,idx[a],idx[b]);} for(int v=1;v<=P;v++) if(pm.vp[v].first<0) return {}; return pm;}

static vector<vector<unsigned char>> graph_from(const CNF&cnf,const PM&pm){ vector<int> sign(pm.P+1); for(int ci=pm.gc*3;ci<(int)cnf.c.size();ci++) for(int lit:cnf.c[ci]) if(abs(lit)<=pm.P) sign[abs(lit)]=lit>0?1:-1; vector<vector<unsigned char>> adj(pm.M, vector<unsigned char>(pm.M)); for(int v=1;v<=pm.P;v++){auto [i,j]=pm.vp[v]; adj[i][j]=adj[j][i]=sign[v]>0;} return adj; }
static int part_cost(const vector<vector<unsigned char>>&adj,const vector<int>&p){int M=adj.size(),cost=0; for(int i=0;i<M;i++)for(int j=i+1;j<M;j++) cost += ((p[i]==p[j]) != (bool)adj[i][j]); return cost;}
static void norm(vector<int>&p){map<int,int> mp; int nxt=0; for(int&x:p){auto it=mp.find(x); if(it==mp.end()) it=mp.emplace(x,nxt++).first; x=it->second;}}
static vector<int> cluster_local(const vector<vector<unsigned char>>&adj,int ms=2000){int M=adj.size(); mt19937 rng(1); vector<int> bestp; int best=INT_MAX; auto deadline=chrono::steady_clock::now()+chrono::milliseconds(ms); int rest=0; while(chrono::steady_clock::now()<deadline && rest<2000){vector<int> p(M); if(rest==0) iota(p.begin(),p.end(),0); else if(rest==1) fill(p.begin(),p.end(),0); else {int k=2+(rng()%max(2,min(M,12))); for(int i=0;i<M;i++) p[i]=rng()%k; norm(p);} int cur=part_cost(adj,p); bool imp=true; while(imp && chrono::steady_clock::now()<deadline){imp=false; vector<int> ord(M); iota(ord.begin(),ord.end(),0); shuffle(ord.begin(),ord.end(),rng); for(int v:ord){int old=p[v]; set<int> labs(p.begin(),p.end()); labs.insert((int)labs.size()); int bd=0,bl=old; for(int lab:labs){ if(lab==old)continue; int delta=0; for(int u=0;u<M;u++) if(u!=v) delta += ((p[u]==lab)!=(bool)adj[u][v])-((p[u]==old)!=(bool)adj[u][v]); if(delta<bd) bd=delta,bl=lab;} if(bd<0){p[v]=bl; norm(p); cur+=bd; imp=true;}} vector<int> labs; {set<int>s(p.begin(),p.end()); labs.assign(s.begin(),s.end());} bool merged=false; for(int ia=0;ia<(int)labs.size()&&!merged;ia++) for(int ib=ia+1;ib<(int)labs.size();ib++){int a=labs[ia],b=labs[ib],delta=0; for(int i=0;i<M;i++) if(p[i]==a) for(int j=0;j<M;j++) if(p[j]==b) delta += (1!=(bool)adj[i][j])-(0!=(bool)adj[i][j]); if(delta<0){for(int&x:p)if(x==b)x=a; norm(p); cur+=delta; imp=merged=true; break;}} }
 if(cur<best){best=cur; bestp=p; fprintf(stderr,"cluster best %d clusters %zu restart %d\n",best,set<int>(p.begin(),p.end()).size(),rest);} rest++; } return bestp; }

struct DPLL{
 const CNF*cnf; const PM*pm; vector<vector<int>> occ; long long nodes=0; chrono::steady_clock::time_point deadline;
 bool lit_true(const vector<signed char>&val,int l){int v=abs(l); return val[v] && ((l>0&&val[v]>0)||(l<0&&val[v]<0));}
 bool propagate(vector<signed char>&val, vector<int> q){size_t h=0; int off=cnf->n; while(h<q.size()){int lit=q[h++]; for(int ci: occ[-lit+off]){auto&cl=cnf->c[ci]; bool sat=false; int un=0,last=0; for(int l:cl){int vl=val[abs(l)]; if(vl&&((l>0&&vl>0)||(l<0&&vl<0))){sat=true;break;} if(!vl){un++; last=l; if(un>1) break;}} if(sat||un>1) continue; if(!un) return false; int v=abs(last), s=last>0?1:-1; if(val[v]&&val[v]!=s)return false; if(!val[v]){val[v]=s; q.push_back(last);}}} return true;}
 pair<int,vector<int>> choose_clause(const vector<signed char>&val,int start){
  for(int ci=start;ci<(int)cnf->c.size();ci++){
   auto&cl=cnf->c[ci]; bool sat=false; vector<int> un;
   for(int l:cl){int vl=val[abs(l)]; if(vl&&((l>0&&vl>0)||(l<0&&vl<0))){sat=true;break;} if(!vl) un.push_back(l);}
   if(!sat) return {ci,un};
  }
  return {-1,{}};
 }
 bool dfs(vector<signed char>&val,int start,int depth){
  if(chrono::steady_clock::now()>deadline) return false;
  nodes++;
  auto [ci,un]=choose_clause(val,start);
  if(ci<0) return true;
  if(un.empty()) return false;
  vector<int> cand;
  for(int l:un) if(abs(l)>pm->P) cand.push_back(l);
  if(cand.empty()) return false;
  sort(cand.begin(),cand.end(),[](int a,int b){
   if((a>0)!=(b>0)) return a>0;
   return abs(a)<abs(b);
  });
  for(int l:cand){
   int v=abs(l),s=l>0?1:-1;
   if(val[v]&&val[v]!=s) continue;
   vector<signed char> nv=val; vector<int> q;
   if(!nv[v]){nv[v]=s; q.push_back(l);}
   if(propagate(nv,q) && dfs(nv,ci+1,depth+1)){val.swap(nv); return true;}
  }
  // Also allow satisfying the clause by making a negative unassigned literal true.
  for(int l:cand){
   l=-l;
   int v=abs(l),s=l>0?1:-1;
   if(val[v]&&val[v]!=s) continue;
   vector<signed char> nv=val; vector<int> q;
   if(!nv[v]){nv[v]=s; q.push_back(l);}
   if(propagate(nv,q) && dfs(nv,ci+1,depth+1)){val.swap(nv); return true;}
  }
  return false;
 }
 bool solve(vector<signed char>&val,int seconds){ occ.assign(2*cnf->n+1,{}); int off=cnf->n; for(int ci=0;ci<(int)cnf->c.size();ci++)for(int l:cnf->c[ci])occ[l+off].push_back(ci); vector<int> init; for(int v=1;v<=cnf->n;v++) if(val[v]) init.push_back(val[v]>0?v:-v); if(!propagate(val,init)) return false; deadline=chrono::steady_clock::now()+chrono::seconds(seconds); bool ok=dfs(val,0,0); fprintf(stderr,"dpll nodes %lld ok %d\n",nodes,(int)ok); return ok; }
};

int main(int argc,char**argv){ if(argc<3){fprintf(stderr,"usage: cluster_dpll formula seconds\n");return 2;} CNF cnf=read_cnf(argv[1]); PM pm=infer(cnf); auto adj=graph_from(cnf,pm); vector<int> part=cluster_local(adj,3000); int cost=part_cost(adj,part); fprintf(stderr,"partition cost %d\n",cost); vector<signed char> val(cnf.n+1); for(int v=1;v<=pm.P;v++){auto [i,j]=pm.vp[v]; val[v]=(part[i]==part[j])?1:-1;} DPLL d; d.cnf=&cnf; d.pm=&pm; bool ok=d.solve(val,atoi(argv[2])); if(!ok){fprintf(stderr,"unknown\n"); return 1;} long bad=0; for(auto&cl:cnf.c){bool sat=false;for(int l:cl)if(d.lit_true(val,l)){sat=true;break;} if(!sat)bad++;} fprintf(stderr,"bad %ld\n",bad); if(bad)return 1; for(int v=1;v<=cnf.n;v++) cout<<(val[v]>0?v:-v)<<(v==cnf.n?" 0\n":" "); return 0; }
