// Enumeration of zero-sum incidence matrices. NUM_COLS and REMAINDER_H // specify the number of columns and the remainder size, respectively. // Row multiplicities (kappa,r) are supplied by the accompanying exhaustive generator. // All pruning uses necessary conditions, enumerated explicitly in the paper. #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using Rat=boost::rational; #ifndef NUM_COLS #define NUM_COLS 10 #endif #ifndef REMAINDER_H #define REMAINDER_H 6 #endif constexpr int N=NUM_COLS,H=REMAINDER_H,MAXT=21; using Mask=bitset<512>; using OMask=bitset<128>; using Big=boost::multiprecision::cpp_int; ofstream certificates; Big gcdBig(Big a,Big b){ if(a<0)a=-a; if(b<0)b=-b; while(b!=0){ Big c=a%b; a=b; b=c; } return a; } pair,Big> integralize(vector const& v){ Big den=1; for(auto &x:v)den=den/gcdBig(den,x.denominator())*x.denominator(); vectorw; for(auto &x:v)w.push_back(x.numerator()*(den/x.denominator())); return { w,den }; } void writeInts(ostream& os,vector const& v){ os<<"["; for(size_t j=0;j v{}; Mask cover{}; OMask overlap{}; bool pure=false; }; struct RowTask { int K,R; vector choices; int maxcover=0; }; long long nodes=0,leaves=0,coef=0,rankbad=0,eqbad=0,found=0,endpoint_pass=0,inconsistent=0,boundsbad=0; int cases=0; int rr(vector>&a,int n,vector&piv){ int i=0; piv.clear(); for(int j=0;j> row_data; vector tasks; vector> P; vectorK; arraycap{}; vector chosen; Mask target{}; vector> subsets; int pureUsed=0; long long ns=0,ls=0,cs=0,es=0; array successor{},predecessor{}; int zeroRow=-1; bool endpoint_ok(){ vectorhead(t,-1); int pureRow=-1; for(int u=0;unext(t,-1); for(int j=0;j=0){ if(b<0||head[b]>=0||a==pureRow||b==pureRow)return false; head[b]=a; next[a]=b; } } for(int u=0;u>a(t,vector(N+1+t)); for(int u=0;upv; int rk=rr(a,N,pv); if(rkused(N,false); for(int j:pv)used[j]=true; int f=0; while(used[f])f++; vectorz(N); z[f]=1; for(int u=0;uy(t); for(int v=0;vmu(N); for(int j=0;j0&&mu[j]<1)){ boundsbad++; baseCertificate("coefficient_bounds"); if(certificates){ certificates<<",\"mu\":["; for(int l=0;lds; for(int u=0;ur(t); for(int v=0;v>b(N,vector(t)); for(int j=0;jqv; int br=rr(b,t,qv); if(br!=N)abort(); vectorisp(t,false); for(int u:qv)isp[u]=true; vectorfree; for(int u=0;u>sig(t,vector(free.size())); for(int q=0;q<(int)free.size();q++){ sig[free[q]][q]=1; for(int j=0;jz(N); for(int j=0;j make(int K,int R){ vector out; arrayv{}; functionrec=[&](int j,int rem,int twos,int threes,int ends){ if(j==N){ if(rem)return; int supp=0; for(auto x:v)supp+=x>0; if(supp<=1)return; Candidate q; q.v=v; q.pure=threes; for(int i=0;iR)q.cover.set(a); } out.push_back(q); return; } int mx=min(rem,j0); if(nt>1||np+pureUsed>1||ne>1||(nt&&np))continue; v[j]=x; rec(j+1,rem-x,nt,np,ne); } v[j]=0; }; rec(0,K+R,0,0,0); sort(out.begin(),out.end(),[](auto&a,auto&b){ int x=a.cover.count(),y=b.cover.count();if(x!=y)return x>y;return a.v>&added,int proposedZero){ int current=P.size(); for(int j=0;j0&&q.v[j]==cap[j]){ int a=-1,b=-1; if(q.v[j]==2){ a=current; for(int u=0;u=0||predecessor[b]>=0)return false; int x=b; while(x>=0){ if(x==a)return false; x=successor[x]; } successor[a]=b; predecessor[b]=a; added.emplace_back(a,b); } return true; } void unstage(vector> const& added){ for(auto[a,b]:added){ successor[a]=-1; predecessor[b]=-1; } } void dfs(int at,Mask covered,OMask overlap,int pure){ nodes++; ns++; if(at==(int)tasks.size()){ for(int x:cap)if(x)return; if((covered&target)==target)check(); return; } Mask missing=target&~covered; int need=missing.count(),upper=0; for(int a=at;a<(int)tasks.size();a++)upper+=tasks[a].maxcover; if(need>upper)return; auto&T=tasks[at]; int start=0; if(at&&T.K==tasks[at-1].K&&T.R==tasks[at-1].R)start=chosen[at-1]; for(int ci=start;ci<(int)T.choices.size();ci++){ auto&q=T.choices[ci]; if((q.overlap&overlap).any())continue; if(q.pure&&pure)continue; bool ok=true; for(int j=0;jcap[j]){ ok=false; break; } if(!ok)continue; // Prefix lexicographic order among otherwise interchangeable normal columns. for(int j=c;j+1q.v[j+1]){ ok=false; break; } } if(!ok)continue; vector>added; int previousZero=zeroRow; int proposedZero=q.pure?(int)P.size():zeroRow; if(!stage_edges(q,added,proposedZero)){ unstage(added); continue; } zeroRow=proposedZero; for(int j=0;jt)return; } successor.fill(-1); predecessor.fill(-1); zeroRow=(p1+p2)?d:-1; cap.fill(3); pureUsed=p1+p2; P.clear(); K.clear(); for(int j=0;jv{}; v[j]=2; P.push_back(v); K.push_back(1); cap[j]=1; } if(pureUsed){ arrayv{}; v[d]=3; P.push_back(v); K.push_back(p1?1:2); cap[d]=0; } vector cur; function comb=[&](int j){ if((int)cur.size()==H-3){ subsets.push_back(cur); return; } for(int l=j;l512)throw runtime_error("mask too short"); for(int i=0;i<(int)subsets.size();i++)target.set(i); for(auto[K,R]:row_data){ RowTask a; a.K=K; a.R=R; a.choices=make(K,R); for(auto&q:a.choices)a.maxcover=max(a.maxcover,(int)q.cover.count()); tasks.push_back(move(a)); } sort(tasks.begin(),tasks.end(),[](auto&a,auto&b){ if(a.maxcover!=b.maxcover)return a.maxcover>b.maxcover;if(a.K!=b.K)return a.K>b.K;return a.R128)throw runtime_error("overlap mask too short"); if(argc>4){ certificates.open(argv[4]); if(!certificates)throw runtime_error("cannot open certificate output"); } int q=0; for(int i=0;i2?stoi(argv[2]):0,parts=argc>3?stoi(argv[3]):1; ifstream in(file); int id,t,d,p1,p2; while(in>>id>>t>>d>>p1>>p2){ vector>row_data; for(int j=0;j>a>>b; row_data.emplace_back(a,b); } if(id%parts!=part)continue; Solver s; s.case_id=id; s.t=t; s.d=d; s.p1=p1; s.p2=p2; s.row_data=row_data; auto tm=chrono::steady_clock::now(); s.run(); cases++; cout<<"case="<