// use inline functions - for SPEEEED! #define INLINE // general includes #include #include #include // panic timer stuff # include # include # include # include #define DEFAULTTIME 60.0 // Problem specific defines: // Maximum width or height of a rectangle (image or the paper) #define MAXDIM_compiletime 5000 int MAXDIM_runtime = MAXDIM_compiletime; #define VERY_BIG_AREA (MAXDIM_compiletime * MAXDIM_compiletime) // for final "wiggling": // How many good solutions to keep, // How many "wiggled" ones to produce, // After how many eventless wiggling rounds to give up #define MAXCHAMPS 30 #define EXTRACHAMPS 1000 #define MAXNOSUCCESSWIGGLE 20 // Hmpf, wiggling doesn't work anyhow # define ASSERT(x) //# define ASSERT_VALID # define AtLeast(a,b) (a)>?=(b) # define AtMost(a,b) (a)=a) b++; else { int t = a; a = b; b = t; } } // This POTM accidentally allows asm, so let's use it. // Hm, this is just the Intel CPU cycle counter // for profiling during debug and for random init. long long mutime() { asm ( "rdtsc;" : : : "eax", "edx" ); } // Some *very* global variables int The_Xmax, The_Ymax; int The_N; int The_MinArea, Optimistic_MinArea; ////////////////////////////////////////////////////////////////////// // This is what were seperate *.h files during original development // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "Minute.h" ////////////////////////////////////////////////////////////////////// class Minute // for timout checks { public: void PanicAt(double restseconds); double Ticks2Secs(int t) { return Factor*t; }; // How many seconds are still left? (Avoid this, it uses too many float ops!) double TimeLeft(); Minute(double howlong=DEFAULTTIME); virtual ~Minute(); // Precalculate " seconds left" to an expected Ticks() return value int TimeremainingTicks(double remain); // raw timer readout int Ticks(); private: double invFactor, Factor; // how to multiply from/to raw ticks / seconds (we prefer FPMUL over slow FPDIV) double Const; // constant part referring to when we have to be finished }; Minute TheMinute; bool volatile PANIC = false; # define IFPANIC if (PANIC) ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "MultiInterval.h" ////////////////////////////////////////////////////////////////////// #define INFTY 2000000000 class MultiInterval { public: static int BestSplit(const MultiInterval& A, const MultiInterval& B, int wA, int wB, int H); int BestSplit(int A, int B, int H); void Empty(); MultiInterval& MakeDiff(const MultiInterval& A, const MultiInterval& B); MultiInterval& MakeSum(const MultiInterval& A, const MultiInterval& B); MultiInterval& OrByAnd(const MultiInterval& A, const MultiInterval& B); void IntIntersect(int Min, int Max); void IntUnion(int a, int b); void PointUnion(int a); bool Contains(int x) const; #ifdef INLINE # define GETMINIMUM(miv) ( (miv).pData[0] ) # define GETMAXIMUM(miv) ( (miv).pData[(miv).N-3] ) # define ISEMPTY(miv) ( !(miv).pData || (miv).pData[0]==INFTY ) # define TISEMPTY ( !pData || pData[0]==INFTY ) # define GETDATA(miv) ( (miv).pData ) #else # define GETMINIMUM(miv) miv.GetMinimum() # define GETMAXIMUM(miv) miv.GetMaximum() # define ISEMPTY(miv) miv.IsEmpty() # define TISEMPTY IsEmpty() # define GETDATA(miv) miv.GetData() int GetMinimum() const { return pData[0]; }; int GetMaximum() const { return pData[N-3]; }; bool IsEmpty() const { return !pData || pData[0]==INFTY; }; const int* GetData() const { return pData; }; #endif MultiInterval(int a, int b); MultiInterval(int* data=NULL, int n=0); MultiInterval(const MultiInterval& copy); virtual ~MultiInterval(); private: void SetN(int n); int Dim; #ifdef INLINE public: #endif int N; int* pData; }; ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "SolutionHolder.h" ////////////////////////////////////////////////////////////////////// class POTMrect; class SolutionHolder { public: bool IsValid(const POTMrect* const Liste[]); void Wiggle(); int MinArea(); int MaxArea(); int AreaSpread() ; bool Better(SolutionHolder& other) ; void Print() const; int FreeArea() ; void SetSizeAndPos(char c, int w, int h, int x, int y); SolutionHolder(); virtual ~SolutionHolder(); int AreaOf(char c) const { return FF[c-'A']; } private: void Relocate(int *A, int *dA, int old, int by); void WiggleDim(int* A, int* dA, int Amax); int KnownArea, KnownSpread; int xx[26], yy[26], ww[26], hh[26]; int FF[26]; }; ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "POTMrect.h" ////////////////////////////////////////////////////////////////////// class POTMrect { friend class SumRect; friend class DiffRect; friend class FlipRect; public: bool CanRealize(int w, int h) const; #ifndef INLINE virtual int GetWeight() const { return Weight; }; #else # define GetWeight() Weight #endif void OrFlip(); virtual void Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const = 0; int ExactMinArea(int&x, int&y) const; int ApproximateMinArea() const; bool IsValid() const; double GetAspectRatio() const; POTMrect(int W=0); virtual ~POTMrect(); void ResetMinArea(int NewMinArea, int NewMaxArea); private: double Aspect; int MinFirst, MaxFirst, MinSecond, MaxSecond; #ifdef INLINE public: #endif int Weight; protected: void SetAspect(int Z, int N); void SetIntval(int a, int bmin, int bmax); MultiInterval Yset[MAXDIM_compiletime+1]; }; ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "Diffrect.h" ////////////////////////////////////////////////////////////////////// class DiffRect : public POTMrect { public: DiffRect(const POTMrect& _RA, const POTMrect& _RB, bool subfromtop); virtual ~DiffRect(); void Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const; private: bool SubFromTop; const POTMrect& RA; const POTMrect& RB; }; ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "FixRect.h" ////////////////////////////////////////////////////////////////////// class FixRect : public POTMrect { public: FixRect(int x, int y); virtual ~FixRect(); void Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const; private: int Xmax, Ymax; }; ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "GivenRect.h" ////////////////////////////////////////////////////////////////////// class GivenRect : public POTMrect { public: char GetName(); void Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const; GivenRect(char name, int x, int y, int min_area); virtual ~GivenRect(); private: char Name; }; ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "SumRect.h" ////////////////////////////////////////////////////////////////////// class SumRect : public POTMrect { public: SumRect(const POTMrect& _RA, const POTMrect& _RB); virtual ~SumRect(); void Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const; private: const POTMrect& RA; const POTMrect& RB; }; ////////////////////////////////////////////////////////////////////// // End of *.h files. // // The rest corresponds to what were seperate *.cpp files during // // development - with all includes removed // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "Minute.cpp" ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// void AlarmHandler(int Signal) { // Signal is always assumed to be SIGPROF PANIC = true; } Minute::Minute(double howlong) : Const(0.0) { invFactor = sysconf(_SC_CLK_TCK); Factor = 1.0 / invFactor; Const = howlong-TimeLeft(); srand((unsigned int)mutime()); struct sigaction MySigAction; MySigAction.sa_handler = AlarmHandler; //MySigAction.sa_mask = 0; MySigAction.sa_flags = 0; sigaction(SIGPROF, &MySigAction, NULL); } Minute::~Minute() { struct sigaction MySigAction; MySigAction.sa_handler = SIG_DFL; //MySigAction.sa_mask = 0; MySigAction.sa_flags = 0; sigaction(SIGPROF, &MySigAction, NULL); } double Minute::TimeLeft() { return Const - Factor *Ticks(); } int Minute::TimeremainingTicks(double remain) { // The smallest value of Ticks() that corresponds // To a remaining time <= remain seconds // remain >= Const - Factor * result return (int) ( (Const - remain)*invFactor ); } int Minute::Ticks() { struct tms dummy; times(&dummy); return dummy.tms_utime + dummy.tms_stime; } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "MultiInterval.cpp" ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// void MyPadMovedown(int* dest, int*src) { for(;;) { if ((*dest++=*src++)==INFTY) { *dest=INFTY; break; } } } void MyPadInsert(int* where, int a, int b) { int u,v; for(;;) { u = where[0]; v=where[1]; where[0]=a; where[1]=b; if (a==INFTY) { break; } a=u; b=v; where+=2; } } MultiInterval::MultiInterval(int a, int b): Dim(0), pData(NULL) { SetN(4); pData[0]=a; pData[1]=b; pData[2]=pData[3]=INFTY; } MultiInterval::MultiInterval(int* a, int n): Dim(0), N(0), pData(NULL) { if (a) { if (!n) { while (a[n]!=INFTY) n+=2; n+=2; } if (n>2) { SetN(n); MyPadMovedown(pData,a); } } } MultiInterval::MultiInterval(const MultiInterval& copy): Dim(0), N(0), pData(NULL) { if (!ISEMPTY(copy)) { SetN(copy.N); MyPadMovedown(pData,copy.pData); } } MultiInterval::~MultiInterval() { delete[] pData; } bool MultiInterval::Contains(int x) const { ASSERT(x=x return p[0]<=x; } void MultiInterval::SetN(int n) { int neuDim = (n|7)+1; if (neuDim>Dim) { int* neu = new int[neuDim]; if (pData) { MyPadMovedown(neu,pData); delete [] pData; } else { neu[0]=neu[1] = INFTY; } pData = neu; Dim = neuDim; ASSERT(pData[0]>=0); } N=n; } void MultiInterval::PointUnion(int a) { ASSERT(a>=0); ASSERT(a=0); ASSERT(b>=a); if (!pData) { SetN(4); pData[0]=a; pData[1]=b; pData[2]=pData[3]=INFTY; return; } int *i1=pData; while (i1[1]j[0]? i[0]:j[0], i[1]j[1]? i[0]-j[1] : 0, i[1]-j[0]); return *this; } MultiInterval& MultiInterval::MakeSum(const MultiInterval &A, const MultiInterval &B) { if ( ISEMPTY(A) || ISEMPTY(B) ) { Empty(); return *this; } SetN(2); pData[0]=pData[1]=INFTY; for (int*i=A.pData; *i!=INFTY; i+=2) { int jlim = MAXDIM_runtime - i[0]; // esp., jlim < INFTY for (int*j=B.pData; j[0]<=jlim; j+=2) { int t; setmin(t, i[1]+j[1], MAXDIM_runtime); IntUnion(i[0]+j[0],t); } } return *this; } void MultiInterval::IntIntersect(int Min, int Max) { if (TISEMPTY) return; int *i = pData; while (i[1] < Min) i+=2; if (i!=pData) { N -= i-pData; MyPadMovedown(pData,i); if (TISEMPTY) return; } AtLeast(pData[0],Min); if (Max == INFTY) return; if (pData[0]>Max) { Empty(); return; } i=pData; while (i[2]<=Max) i+=2; i[2]=i[3]=INFTY; N = (i-pData)+4; AtMost(i[1], Max); } void MultiInterval::Empty() { Dim = 0; N = 0; if (pData) delete[] pData; pData=NULL; } int MultiInterval::BestSplit(int A, int B, int H) { /* Find x such that x:(H-x)=A:B holds as good as possible. More precisely, maximize min(x/A, (H-x)/B) Or equivalently, maximize f(x) = min(B*x, A*(H-x)) Obviously, approximately x=(H*A)/(A+B) is best: if x=(H*A)/(A+B), then f(x) = min(HAB/(A+B), (HA(A+B)-HAA)/(A+B)) = HAB/(A+B) if x<=(H*A)/(A+B), then f(x-eps)=f(x)-B*eps if x>=(H*A)/(A+B), then f(x+eps)=f(x)-A*eps Best candidates: int C1 = Floor( (H*A)/(A+B) ), C2=Ceiling( (H*A)/(A+B) ); Best point within [a,b]: if (A+B)*bH*A (i.e. a>= C2): a else (a f(C1)-f(C2) = A*C2+B*C1-A*H, C2 is better than C1 if A*C2+B*C1C1 (INFTY?), pData[i-1]<=C1 (but possibly i==0) if (i&1) { // C1 in interval: [ pData[i-1] <= C1 < pData[i] ] if (C1!=C2 && A*C2+B*C1C1 and hence >=C2 } else { // C1 more or less outside interval: // [... pData[i-1] ] <= C1,C2 <= [ pData[i] ... ] (=INFTY?) // (INFTY would overflow the comparison) if (pData[i] H) { if (j==B.pData) break; j-=2; } else { // There is overlap int lo, hi; setmax(lo,i[0], H-j[1]); setmin(hi,i[1], H-j[0]); result.IntUnion( lo, hi ); if (i[1] == hi ) { i+=2; if (i[0]==INFTY) break; } else { if (j==B.pData) break; j-=2; } } } return result.BestSplit(wA,wB,H); } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "SolutionHolder.cpp" ////////////////////////////////////////////////////////////////////// // SolutionHolder.cpp: Implementierung der Klasse SolutionHolder. // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// SolutionHolder::SolutionHolder(): KnownArea(-1), KnownSpread(-1) { for (char c='A'; c<='Z'; c++) SetSizeAndPos(c,0,0,0,0); } SolutionHolder::~SolutionHolder() { } void SolutionHolder::SetSizeAndPos(char c, int w, int h, int x, int y) { c-='A'; xx[(int)c]=x; yy[(int)c]=y; ww[(int)c]=w; hh[(int)c]=h; FF[(int)c]=w*h; } int SolutionHolder::FreeArea() { if (KnownArea>=0) return KnownArea; int ac=0; for (int i=0; i=0) return KnownSpread; return KnownSpread = MaxArea() - MinArea(); } void SolutionHolder::Wiggle() { WiggleDim(xx,ww,The_Xmax); WiggleDim(yy,hh,The_Ymax); } bool SolutionHolder::IsValid(const POTMrect* const Liste[]) { for (int i=0; iCanRealize(ww[i],hh[i])) return false; return true; } void SolutionHolder::WiggleDim(int *A, int *dA, int Amax) { MultiInterval Aset; for (int i=0; i=0); ASSERT(dA[i]>0); ASSERT(A[i]+dA[i]<=Amax); if (A[i]) Aset.PointUnion(A[i]); if (A[i]+dA[i] < Amax) Aset.PointUnion(A[i]+dA[i]); } for (const int* pi=GETDATA(Aset); pi[0]!=INFTY; pi+=2) { int front,back; RNDpair(pi[1]-pi[0]+3, front, back); front += pi[0]; back += pi[0]-2; int k; for (k=pi[0]; kback; k--) Relocate(A,dA,k,+1); } } void SolutionHolder::Relocate(int *A, int *dA, int old, int by) { for (int i=0; i=1) return Aspect; int L = (MaxFirst+MinFirst)>>1; double a = (GETMINIMUM(Yset[L])+GETMAXIMUM(Yset[L]))/(double)(L+L); if (a<1) return 1/a; return a; } bool POTMrect::IsValid() const { return MaxSecond >= MinSecond; } void POTMrect::SetIntval(int a, int bmin, int bmax) { AtMost(bmax,MAXDIM_runtime); AtLeast(bmin,0); if (bmax=MinFirst;i--) { const int* pi = GETDATA(Yset[i]); if (!pi) continue; for ( ; *pi!=INFTY; pi+=2) { IFPANIC break; for (int j=pi[0]; j<=pi[1]; j++) Yset[j].PointUnion(i); } } AtLeast(MaxFirst,MaxSecond); AtLeast(MaxSecond,MaxFirst); AtMost(MinFirst,MinSecond); AtMost(MinSecond,MinFirst); } bool POTMrect::CanRealize(int w, int h) const { return w>=0 && w<=MAXDIM_compiletime && Yset[w].Contains(h); } void POTMrect::ResetMinArea(int NewMinArea, int NewMaxArea) { for (int i=MinFirst; i<=MaxFirst; i++) Yset[i].IntIntersect( (NewMinArea-1)/i +1 , NewMaxArea/i); while (MaxFirst > MinFirst && ISEMPTY(Yset[MaxFirst])) MaxFirst--; while (MinFirst < MaxFirst && ISEMPTY(Yset[MinFirst])) MinFirst++; MinSecond = MinFirst; MaxSecond = MaxFirst; } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "DiffRect.cpp" ////////////////////////////////////////////////////////////////////// // DiffRect.cpp: Implementierung der Klasse DiffRect. // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// DiffRect::DiffRect(const POTMrect& _RA, const POTMrect& _RB, bool subfromtop): POTMrect(_RA.Weight + _RB.Weight), SubFromTop(subfromtop), RA(_RA), RB(_RB) { if (SubFromTop) { int i, i1; setmax(i,RA.MinFirst,RB.MinFirst); setmin(i1,RA.MaxFirst,RB.MaxFirst); for ( ; i<=i1; i++) { Yset[i].MakeDiff(RA.Yset[i],RB.Yset[i]); // IFPANIC return; if (!ISEMPTY(Yset[i])) { Between(MinFirst,i,MaxFirst); Between4(MinSecond,GETMINIMUM(Yset[i]), GETMAXIMUM(Yset[i]),MaxSecond); ASSERT(MinSecond>=0); } } } else { int j1; setmin(j1,RB.MaxFirst,RA.MaxFirst); for (int j=RB.MinFirst; j<=j1; j++) if (!ISEMPTY(RB.Yset[j])) { int ij; setmax(ij,j,RA.MinFirst); IFPANIC return; for ( ; ij<=RA.MaxFirst; ij++) if (!ISEMPTY(RA.Yset[ij])) { Yset[ij-j].OrByAnd(RA.Yset[ij], RB.Yset[j]); } } for (int i=0; i<=RA.MaxFirst; i++) if (!ISEMPTY(Yset[i])) { Between(MinFirst,i,MaxFirst); Between4(MinSecond,GETMINIMUM(Yset[i]),GETMAXIMUM(Yset[i]),MaxSecond); } } ASSERT(MinFirst>=0); ASSERT(MinSecond>=0); } DiffRect::~DiffRect() { } void DiffRect::Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const { ASSERT(W>=0 && W<=The_Xmax); ASSERT(H>=0 && H<=The_Ymax); ASSERT(Yset[W].Contains(H)); /* Plan: make the inner rect as big as possible (?) Because, typically, the most-stretched and thus biggest rects are located on the outer border and will benefit from being squeezed a bit */ /* NEW: area:totalarea = weight:totalweight */ // find intvals of h where W ok, if (SubFromTop) { MultiInterval Temp; int Hmin; setmax(Hmin, GETMINIMUM(RA.Yset[W]), H+GETMINIMUM(RB.Yset[W])); int ha; setmin(ha,GETMAXIMUM(RA.Yset[W]), H+GETMAXIMUM(RB.Yset[W])); for ( ; ha>=Hmin; ha--) if (RA.Yset[W].Contains(ha) && RB.Yset[W].Contains(ha-H)) Temp.PointUnion(ha-H); ASSERT(!ISEMPTY(Temp)); // W* x ~ RB.weight * OptimisticArea //maximize // min( W*x/RB.weight, ((RA.wt+RB.wt)*Optim - W*x )/RA.wt ) // min( RA.wt*W * x, RB.wt*W ((RA.wt+RB.wt)*Optim/W - x) int Ch = Temp.BestSplit(RB.GetWeight()*W, RA.GetWeight()*W, ((RA.GetWeight()+RB.GetWeight())*Optimistic_MinArea) / W ); RA.Realize(X0, Y0, W, Ch+H, cand); RB.Realize(X0, Y0+H, W, Ch, cand); } else { MultiInterval Temp; int Wmin; setmax(Wmin,RA.MinFirst, W+RB.MinFirst); int wa; setmin(wa,RA.MaxFirst, W+RB.MaxFirst); for ( ; wa>=Wmin ; wa--) if (RA.Yset[wa].Contains(H) && RB.Yset[wa-W].Contains(H)) Temp.PointUnion(wa-W); ASSERT(!ISEMPTY(Temp)); int Cw = Temp.BestSplit(RB.GetWeight()*H, RA.GetWeight()*H, ((RA.GetWeight()+RB.GetWeight())*Optimistic_MinArea) / H ); RA.Realize(X0, Y0, Cw+W, H, cand); RB.Realize(X0+W, Y0, Cw, H, cand); } } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "FixRect.cpp" ////////////////////////////////////////////////////////////////////// // FixRect.cpp: Implementierung der Klasse FixRect. // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// FixRect::FixRect(int x, int y): Xmax(x), Ymax(y) { SetIntval(x,y,y); SetAspect(x,y); } FixRect::~FixRect() { } void FixRect::Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const { ASSERT(W==Xmax && H==Ymax); } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "GivenRect.cpp" ////////////////////////////////////////////////////////////////////// // GivenRect.cpp: Implementierung der Klasse GivenRect. // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// GivenRect::GivenRect(char name, int x, int y, int min_area): POTMrect(1), Name(name) { if (x>y) { int t=x; x=y; y=t; } SetAspect(x,y); // We could use The_Xmax, The_Ymax instead of MAXDIM_runtime // but let's keep the data flip-symmetric for (int u=1; u<=MAXDIM_runtime; u++) { // ?? with // abs(??/u-y/x) <= 1/50 // abs(50x*?? - 50uy) <= ux int yhi = ((50*y+x) * u) / (50*x); int ylo = ((50*y-x) * u -1) / (50*x) +1; AtMost(yhi,MAXDIM_runtime); AtLeast(ylo,u); AtLeast(ylo, (min_area-1)/u+1 ); if (ylo<=yhi) SetIntval(u, ylo, yhi); // ?? with // abs(u/??-y/x) <= 1/50 // abs(50ux - 50y*??) <=x*?? // (50y-x)*?? <= 50ux <= (50y+x)*?? yhi = (50*u*x)/(50*y-x); ylo = (50*u*x -1)/(50*y+x) +1; AtMost(yhi,MAXDIM_runtime); AtMost(yhi,u); AtLeast(ylo, (min_area-1)/u+1 ); if (ylo<=yhi) SetIntval(u, ylo, yhi); } } GivenRect::~GivenRect() { } void GivenRect::Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const { ASSERT(W<=The_Xmax); ASSERT(H<=The_Ymax); ASSERT(H>0); ASSERT(W>0); ASSERT( Yset[W].Contains(H)); cand.SetSizeAndPos(Name,W,H,X0,Y0); } char GivenRect::GetName() { return Name; } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "SumRect.cpp ////////////////////////////////////////////////////////////////////// // SumRect.cpp: Implementierung der Klasse SumRect. // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// SumRect::SumRect(const POTMrect& _RA, const POTMrect& _RB): POTMrect(_RA.Weight + _RB.Weight), RA(_RA), RB(_RB) { int i,i1; setmax(i,RA.MinFirst,RB.MinFirst); setmin(i1,RA.MaxFirst,RB.MaxFirst); for ( ; i<=i1; i++) { Yset[i].MakeSum(RA.Yset[i],RB.Yset[i]); // IFPANIC return; if (!ISEMPTY(Yset[i])) { Between(MinFirst,i,MaxFirst); Between4(MinSecond,GETMINIMUM(Yset[i]),GETMAXIMUM(Yset[i]),MaxSecond); } } OrFlip(); } SumRect::~SumRect() { } void SumRect::Realize(int X0, int Y0, int W, int H, SolutionHolder& cand) const { ASSERT(W>=0 && W<=The_Xmax); ASSERT(H>=0 && H<=The_Ymax); // Use the fact that we are flip-symmetric (or aren't we?) int Ch = MultiInterval::BestSplit(RA.Yset[W], RB.Yset[W], RA.Weight, RB.Weight, H); int Cw = MultiInterval::BestSplit(RA.Yset[H], RB.Yset[H], RA.Weight, RB.Weight, W); if (Cw>=0 && Ch>=0) { int wertH = RB.Weight*Ch; AtMost(wertH,RA.Weight*(H-Ch)); int wertW = RB.Weight*Cw; AtMost(wertW,RA.Weight*(W-Cw)); if (wertH>wertW) Cw=-1; // Don't use Cw; Ch is better } if (Cw<0) { ASSERT(Ch>=0); RA.Realize(X0,Y0, W,Ch, cand); RB.Realize(X0,Y0+Ch,W,H-Ch,cand); } else { RA.Realize(X0, Y0,Cw, H,cand); RB.Realize(X0+Cw,Y0,W-Cw,H,cand); } } ////////////////////////////////////////////////////////////////////// // ORIGINAL FILE: "POTM.cpp" // This is where I could knit it all together ;) ////////////////////////////////////////////////////////////////////// #define COLLECTIONSIZE 5 class potmcollection { public: potmcollection() { for (int i=0; iResetMinArea(NewMinArea, NewMaxArea); } char GetName() { return ((GivenRect*)combi[0])->GetName(); } POTMrect *combi[COLLECTIONSIZE]; }; potmcollection Liste[26]; POTMrect* InputListe[26]; bool ReadInput(FILE* in) { if (fscanf(in,"PAGE %d %d", &The_Xmax, &The_Ymax) != 2) return false; setmax(MAXDIM_runtime, The_Xmax, The_Ymax); The_MinArea = (The_Xmax * The_Ymax)/100; The_N=0; char c; int xx,yy; int r; while ((r=fscanf(in, " %c %d %d",&c, &xx, &yy))==3) { if (c!=The_N+'A') { return false; } InputListe[The_N] = new GivenRect(c,xx, yy, The_MinArea); Liste[The_N].combi[0] = new GivenRect(c,xx, yy, The_MinArea); The_N++; } Optimistic_MinArea = (The_Xmax * The_Ymax) / The_N; return true; } void SortByAspect() { for (int i=0; iGetAspectRatio()>Liste[j].combi[0]->GetAspectRatio()) Liste[i].SwapWith(Liste[j]); } #define ALLCHAMPS (MAXCHAMPS+EXTRACHAMPS) SolutionHolder Champion[ALLCHAMPS]; int HaveChamps = 0; // How many improvements have been found during this run of BT? int BTcounter = 0; // How many complete BT's without improvement have we suffered? int BTbad = 0; // Set to true if main score == 0 (i.e. all pixels can be covered) bool BTlimit = false; #define PAPER_IS_SYMMETRIC 666 #define PAPER_IS_ASYMMETRIC 999 int BT(const potmcollection L[], int N, const POTMrect& Paper, int lastCombi, bool lastFromTop) { if (!Paper.IsValid()) return 0; if (!N) { if (Paper.ApproximateMinArea() <= Champion->FreeArea() ) { int xx,yy; int Area = Paper.ExactMinArea(xx,yy); if (Area <= Champion->FreeArea()) { SolutionHolder Candidate; Paper.Realize(0,0,xx,yy, Candidate); if (Candidate.Better(Champion[0])) { if (HaveChamps0; i--) Champion[i] = Champion[i-1]; Champion[0] = Candidate; if (Candidate.FreeArea()==0) { BTlimit = true; // find Liste wise extreme of Candidate... int Amin = Candidate.MinArea(); int Amax = Candidate.MaxArea(); int minfd=0, maxfd=0; for (int i=0; i 30 && Champion[3].FreeArea() == Champion->FreeArea()) TheMinute.PanicAt(30.0); } } } return 0; } for (int ic=COLLECTIONSIZE-1; ic>=0; ic--) { int cwt, returnto; POTMrect *pc, *pRest; if ((pc=L[0].combi[ic])!=NULL && (cwt = pc->GetWeight())<=N ) { // A zero area would have been found by combi[1] // (we ignore the rare case that we had no time to compute it) if (BTlimit && N==2 && cwt==1) continue; // Certain combis taken from the same side would have been tested before...: // MakeCombi(1,0,0,6.0); // MakeCombi(2,0,1,6.0); // MakeCombi(3,1,1,6.0); // if (PreparationTook>0) MakeCombi(4,1,2,6.0); bool CombiRepeat = (ic<=2) && (lastCombi<=2); if ((ic==2) || (lastCombi==2)) CombiRepeat = (ic+lastCombi==3); if (lastCombi==PAPER_IS_SYMMETRIC) CombiRepeat=true; if (!CombiRepeat || !lastFromTop) { IFPANIC { return The_N; } pRest = new DiffRect(Paper,*pc,true); returnto=BT(L+cwt,N-cwt,*pRest,ic,true); delete pRest; if (returnto>N) return returnto; } // Paper is not but combi[] is flip-symmetric // A final subtraction to zero area would have been found above if (BTlimit && N==cwt) continue; if (!CombiRepeat || lastFromTop) { IFPANIC { return The_N; } pRest = new DiffRect(Paper,*pc,false); returnto=BT(L+cwt,N-cwt,*pRest,ic,false); delete pRest; if (returnto>N) return returnto; } } } return 0; } void MakeCombi(unsigned dest, unsigned src1, unsigned src2, double TimeLimit) { ASSERT(src1GetWeight())>=The_N) continue; POTMrect *pB = Liste[i2].combi[src2]; if (!pB) continue; Liste[i].combi[dest] = new SumRect(*pA, *pB); } } int main(int argc, char* argv[]) { FILE* in = argc? fopen(argv[1],"rt") : NULL; bool readok = ReadInput(in? in : stdin); if (in) fclose(in); if (!readok) { return 1; } SortByAspect(); FixRect Paper(The_Xmax,The_Ymax); double PreparationTook = 0.0; double CombiPanic = 30.0; double BtPanic = 22.0; for(;;) { double begin_prep = TheMinute.TimeLeft(); MakeCombi(1,0,0,CombiPanic); MakeCombi(2,0,1,CombiPanic); MakeCombi(3,1,1,CombiPanic); if (PreparationTook>0) MakeCombi(4,1,2,CombiPanic); PreparationTook = begin_prep - TheMinute.TimeLeft(); TheMinute.PanicAt(BtPanic); BTcounter = 0; BT(Liste, The_N, Paper, The_Xmax==The_Ymax? PAPER_IS_SYMMETRIC : PAPER_IS_ASYMMETRIC, true); CombiPanic = (CombiPanic + 1.5)/2.0; BtPanic = (BtPanic + 1.5) / 2.0; TheMinute.PanicAt(1.6); if (!BTcounter) { BTbad++; if (BTbad>2000) { break; } } if (!Liste[0].combi[1]) { break; } if (The_MinArea == Optimistic_MinArea) { break; } setmin( The_MinArea, Champion->MinArea()+1 /* MAXDIM_runtime/3 */, Optimistic_MinArea); int MyMaxArea; setmax(MyMaxArea, Champion->MaxArea()-1 /* MAXDIM_runtime/3 */, Optimistic_MinArea+1); bool ok=true; for (int i=0; iIsValid()) ok=false; } if (!ok) { break; } // partial remix { for (int i=1; ik; t--) Darwin[t]=Darwin[t-1]; Darwin[k] = j; if (j>=HaveChamps) { UselessLoops = 0; imps++; } } } for (int k=nDarwin-1; k>=0; k--) if (Darwin[k]!=k) Champion[k] = Champion[Darwin[k]]; HaveChamps = nDarwin; } Champion->Print(); for (int id=0; id3.0) alarmseconds+=1.0; if (alarmseconds>0.1) { itimerval alarmdata; alarmdata.it_interval.tv_sec=alarmdata.it_interval.tv_usec=0; alarmdata.it_value.tv_sec=(int)alarmseconds; alarmdata.it_value.tv_usec=(int)(1e6*(alarmseconds-alarmdata.it_value.tv_sec)); setitimer(ITIMER_PROF,&alarmdata,NULL); PANIC = false; } else PANIC = true; }