/* POTM ENTRY: shroud_of_Turan */ /* Your Name: Ted Alper */ /* Your email: alper@epgy.stanford.edu */ /* compile instructions: save in file shroud_of_Turan.java */ /* compile and run as any java program. */ /* (compiling will create five .class files */ import java.util.Vector; import java.util.Random; public class shroud_of_Turan { public static void main(String args[]){ /**** INITIALIZATION ********************************/ shroud_of_Turan st = new shroud_of_Turan( Integer.parseInt(args[0])); if (args.length > 1){ st.DEBUGGING = true; }; /****** ATTACK SUBPROBLEMS *******************************/ while (st.getTime() < (st.DEBUGGING ? 30 : 580)){ //time should be enough for all quick refinements st.addTopProblem(); for (int i=st.Subproblems.size()-1;i>=0;i--){ st.refineProblem(i); }; st.addBottomProblem(); }; /**** PICK 3 BEST SUBPROBLEMS ***************************/ //resolve ties based on ticketsum? overkill. very low priority. int [] [] Subscores = new int[st.Subproblems.size()][5]; for (int i=0;i= st.Subproblems.size()){ continue; }; for (int x=0; x<5; x++){ TestSubscores[x] = Subscores[i][x] + Subscores[j][x] + Subscores[k][x]; }; TestTicketCount = TestSubscores[0] + TestSubscores[1] + TestSubscores[2]; TestTicketCount += TestSubscores[3]; if (TestSubscores[4] > TestSubscores[3]){ TestTicketCount += (TestSubscores[4] - TestSubscores[3] + 1)/2; }; if (TestTicketCount < BestTicketCount){ BestTicketCount = TestTicketCount; BestThree[0]= i; BestThree[1]=j; BestThree[2]=k; }; }; }; /***** ASSIGN BALL VALUES ****/ TuranProblem [] Winners = new TuranProblem[3]; int [] [] BallAssignments = new int[3][]; Vector [] SortedIndicesWithinCover = new Vector[3]; int [] counters = new int[3]; int [] currentmaxs = new int[3]; for (int i=0;i<3;i++){ Winners[i] = (TuranProblem) st.Subproblems.elementAt(BestThree[i]); BallAssignments[i] = new int[Winners[i].HowManyBalls]; SortedIndicesWithinCover[i] = Winners[i].cm.sortBallsByFrequency(); counters[i] = Winners[i].HowManyBalls-1; currentmaxs[i] = Winners[i].cm.TicketsPerBall[((Integer) SortedIndicesWithinCover[i].elementAt(counters[i])).intValue()]; }; for (int ballvalue=1;ballvalue<=st.N;ballvalue++){ // 1st get b to row with currentmax int b=0; for (int i=1;i<3;i++){ if (currentmaxs[i]>currentmaxs[b]){ b=i; }; }; // 2nd assign the right element of bth row to ballvalue BallAssignments[b][ ((Integer) SortedIndicesWithinCover[b].elementAt(counters[b])).intValue()]=ballvalue; counters[b]--; if (counters[b]<0){ currentmaxs[b]=-1; } else{ currentmaxs[b] = Winners[b].cm.TicketsPerBall[((Integer) SortedIndicesWithinCover[b].elementAt(counters[b])).intValue()]; }; }; /****** PRINT OUT AND END*********************/ //first pass: tickets of length > 4 are printed out, tickets of //length 4 are put in a vector of 4-vecs, tickets of length 3 //are put in a vector of 3-vecs. //second pass: 4s and 3s come out, merged as best as possible. for (int i=0;i<3;i++){ for (int j=0;j< Winners[i].cm.FullTickets.size();j++){ st.printTicket( ((Ticket) Winners[i].cm.FullTickets.elementAt(j)).toFinalForm(BallAssignments[i])); }; for (int j=0;j 7) && (getTime() < 500)){ Subproblems.insertElementAt(new TuranProblem(--ZeroIs),0); ( (TuranProblem) Subproblems.firstElement()).initialmethod(); if (DEBUGGING){ int [] deb = ((TuranProblem) Subproblems.firstElement()).cm.getTicketCount(); System.out.println("New Bottom: " + ((TuranProblem) Subproblems.firstElement()).HowManyBalls + " count: " + deb[0] + " " + deb[1] + " " + deb[2] + " " + deb[3] + " " + deb[4]); }; }; }; void refineProblem(int i){ //do a quick refine, then add a time check for the full monty if ( i < Subproblems.size() - 1){ biggercheck(i); }; if (i > 0){ smallercheck(i); }; if (getTime() < 500){ nextmethodcheck(i); }; }; void biggercheck(int i){ TuranProblem bigtp = ( (TuranProblem) Subproblems.elementAt(i+1)); TuranProblem tp = ( (TuranProblem) Subproblems.elementAt(i)); int [] bigcount = bigtp.cm.getTicketCount(); for (int j=0;j0;k--){ testcount[k] = bigcount[k] - testcount[k] + testcount[k-1]; }; testcount[0]=bigcount[0] - testcount[0]; if (tp.cm.isBetter(testcount)==false){ tp.remake(bigtp, j); if (DEBUGGING){ int [] deb = tp.cm.getTicketCount(); System.out.println("bigcheck worked for: " + tp.HowManyBalls + " count: " + deb[0] + " " + deb[1] + " " + deb[2] + " " + deb[3] + " " + deb[4]); }; }; }; }; void smallercheck(int i){ TuranProblem smalltp = ( (TuranProblem) Subproblems.elementAt(i-1)); int [] smallcount = smalltp.cm.getTicketCount(); TuranProblem tp = ( (TuranProblem) Subproblems.elementAt(i)); for (int j=0;j0){ output += balls[i] + " "; if (balls[i]<=7){ lowballs[balls[i]]++; }; } else { while (lowballs[lowcounter]>0){ lowcounter++;}; output += lowcounter + " "; lowballs[lowcounter]++; }; }; System.out.println(output); }; void printTicket( int[] balls, int[] moreballs){ int i=0; while (balls[i]>0){i++;}; for (int j=0;j<7-i;j++){ balls[i+j] = moreballs[j]; }; printTicket(balls); }; } //ends shroud_of_Turan class /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ class Ticket implements MethodParameters{ CoverManager context; int FreeSlots; int [] TheBalls; public String toString(){ //only for testing String output = ""; for (int i=0;i<7-FreeSlots;i++){ output = output + " " + TheBalls[i]; }; return output; }; int [] toFinalForm(int [] BallAssignments){ // just assigns values, leaves 0 in unfilled spots // (remember ball assignments start from 1) int [] output = new int[7]; for (int i=0;i<7-FreeSlots;i++){ output[i] = BallAssignments[TheBalls[i]]; }; return output; }; Ticket(CoverManager thecontext){ TheBalls = new int[7]; FreeSlots = 7; context = thecontext; }; Ticket(CoverManager thecontext, int[] InitialBalls){ this(thecontext); for (int i=0; i< InitialBalls.length;i++){ addBall(InitialBalls[i]); }; }; void addBall(int NewBall){ /* put newball in place, it helps to keep them ordered */ int slot=0; while ( (NewBall > TheBalls[slot]) && (slot < 7-FreeSlots)){ slot++; }; int shiftslot=7-FreeSlots; while (shiftslot>slot){ TheBalls[shiftslot] = TheBalls[shiftslot-- -1]; }; TheBalls[slot] = NewBall; /* now do minor bookkeeping */ FreeSlots--; context.TicketsPerBall[NewBall]++; /* now add triples covered for all triples involving newball */ for (int i=0; i TheBalls[slot]) && (slot < 7-FreeSlots)){ slot++; }; int shiftslot=slot; FreeSlots++; while (shiftslot<7-FreeSlots){ TheBalls[shiftslot] = TheBalls[shiftslot++ +1]; }; context.TicketsPerBall[BadBall]--; /* now subtract triples covered for all triples involving newball */ for (int i=0; i SetOfBalls[seti]){ addBall(SetOfBalls[seti]); seti++; continue; }; ticketi++; seti++; }; while (seti < SetOfBalls.length){ //could be some extra balls here. addBall(SetOfBalls[seti]); seti++; }; }; void mergeSet(Ticket OtherTicket){ int [] tempset = new int[7-OtherTicket.FreeSlots]; for (int i=tempset.length - 1; i>-1;i--){ tempset[i] = OtherTicket.TheBalls[i]; OtherTicket.removeBall(tempset[i]); }; mergeSet(tempset); }; int gaugeBall(int TestBall){ return gaugeBall(TestBall, initialparameters); }; int gaugeBall(int TestBall, int [][] method){ int output=0; int i = 0; while ( (i< 6-FreeSlots) && (TheBalls[i] < TestBall)){ for (int j=i+1; j<7-FreeSlots; j++){ if ( (TheBalls[j]< TestBall) && (context.isCovered(TheBalls[i],TheBalls[j],TestBall)==false)) { // output += a *(6- i) + b*(6-j)+ c*(6-j); // - 2*FreeSlots output += method[2][0] + method[2][1]*(6-method[1][0]*FreeSlots - i) + method[2][2]*(6-method[1][0]*FreeSlots-j); }; if ( (TheBalls[j] > TestBall) && (context.isCovered(TheBalls[i],TestBall,TheBalls[j])==false)){ output += method[3][0] + method[3][1]*(6-method[1][0]*FreeSlots - i) + method[3][2]*(6-method[1][0]*FreeSlots-j); }; }; i++; }; //now i is either at the last ok index or at the first index of a ball // greater than or equal to testball if (TheBalls[i] == TestBall){ return -1; }; while ( i < 6-FreeSlots){ for (int j=i+1;j<7-FreeSlots;j++){ if (context.isCovered(TestBall,TheBalls[i],TheBalls[j])==false){ output += method[4][0] + method[4][1]*(6-method[1][0]*FreeSlots - i) + method[4][2]*(6-method[1][0]*FreeSlots-j); }; }; i++; }; return output; }; int findBestBall(int startball, int [][] method, boolean isstrict){ int outputball=-1; int bestgauge = 0; if (isstrict == false){ bestgauge = 1; }; int testgauge = 0; if (FreeSlots==0){ return -1; }; for (int testball=startball; testball bestgauge) || ( (testgauge==bestgauge) && (isstrict==false))){ outputball = testball; bestgauge = testgauge; }; }; return outputball; }; int findBestBall() { return findBestBall(TheBalls[0]+1); }; int findBestBall(int startball){ return findBestBall(startball, initialparameters); }; int findBestBall(int[][] method, boolean isstrict){ return findBestBall(TheBalls[0]+1,method,isstrict); }; int findBestBall(int[] [] method){ return findBestBall(method, (method[0][0]==1)? true: false); }; int findBestBall(int startball, int[] [] method){ return findBestBall(startball, method, (method[0][0]==1)? true: false); }; int findBestBall(int startball, boolean isstrict){ return findBestBall(startball, initialparameters , isstrict); }; boolean isTicketRedundant(){ /**************** return true if EVERYTHING covered in the ball is covered by other tickets (loop through all triples... if you ever get one that ISN'T redundant, then return false....otherwise drop to end and return true) ******************/ return false; }; void removeRedundantBalls(){ //temporary approach! -- not ideal. int testball; int bestball; for (int i=0;i<7-FreeSlots;i++){ testball = TheBalls[i]; removeBall(testball); bestball = findBestBall(0); if (bestball==-1){ i--; continue; }; addBall(bestball); }; }; } /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ class TuranProblem implements MethodParameters{ int HowManyBalls; CoverManager cm; int whichparameter; TuranProblem(int x){ HowManyBalls = x; cm = new CoverManager(x); whichparameter = 0; }; void remake(TuranProblem bettertp, int Ball){ if (bettertp.HowManyBalls == (HowManyBalls+1)){ cm = new CoverManager(HowManyBalls); for (int i=0; i < bettertp.cm.FullTickets.size();i++){ Ticket betterticket = (Ticket) bettertp.cm.FullTickets.elementAt(i); Ticket myticket = strip(betterticket,Ball); if (myticket.FreeSlots >0){ cm.PartialTickets.addElement(myticket); } else { cm.FullTickets.addElement(myticket); }; }; for (int i=0; i < bettertp.cm.PartialTickets.size();i++){ Ticket betterticket = (Ticket) bettertp.cm.PartialTickets.elementAt(i); Ticket myticket = strip(betterticket,Ball); if (myticket.FreeSlots < 5){ cm.PartialTickets.addElement(myticket); }; }; }; // end case of stripping down from N+1 if (bettertp.HowManyBalls == (HowManyBalls-1)){ for (int i=0; i < cm.FullTickets.size();i++){ Ticket tempticket = (Ticket) cm.FullTickets.elementAt(i); if (tempticket.ballInTicket(Ball)){ continue; } cm.FullTickets.removeElementAt(i--); while ( tempticket.FreeSlots < 7){ tempticket.removeBall(tempticket.TheBalls[6-tempticket.FreeSlots]); }; }; for (int i=0; i < cm.PartialTickets.size();i++){ Ticket tempticket = (Ticket) cm.PartialTickets.elementAt(i); if (tempticket.ballInTicket(Ball)){ continue; } cm.PartialTickets.removeElementAt(i--); while ( tempticket.FreeSlots < 7){ tempticket.removeBall(tempticket.TheBalls[6-tempticket.FreeSlots]); }; }; for (int i=0; i < bettertp.cm.FullTickets.size();i++){ Ticket betterticket = (Ticket) bettertp.cm.FullTickets.elementAt(i); Ticket myticket = new Ticket(cm, betterticket.TheBalls); cm.FullTickets.addElement(myticket); }; for (int i=0; i < bettertp.cm.PartialTickets.size();i++){ Ticket betterticket = (Ticket) bettertp.cm.PartialTickets.elementAt(i); Ticket myticket = new Ticket(cm, betterticket.TheBalls); cm.PartialTickets.addElement(myticket); }; }; }; Ticket strip(Ticket bt, int Ball){ Ticket output = new Ticket(cm); for (int j=0;j<7-bt.FreeSlots;j++){ if (bt.TheBalls[j] == Ball){ continue; }; if (bt.TheBalls[j]==HowManyBalls){ output.addBall(Ball); continue; }; output.addBall(bt.TheBalls[j]); }; return output; }; void initialmethod(){ basicmethod(initialparameters); }; void basicmethod(int whichparameterset){ whichparameter = whichparameterset; if (whichparameterset < goodparameters.length){ basicmethod(goodparameters[whichparameterset]); } else { //COME BACK HERE AND MAKE UP GOOD ONES! basicmethod(initialparameters); }; }; /***************************************** general method is boggle-like. make new tickets and continually add the next ball to the ticket that maximizes weight. ******************************************/ void basicmethod(int [][] params){ // startwithdisjointtickets(); int [] Focus = {0,1,2}; Focus = cm.getNextUncovered(Focus); int nextball = -1; while (Focus[0] != -1){ Ticket ct = new Ticket(cm, Focus); do { nextball = ct.findBestBall(params); if (nextball > -1) { ct.addBall(nextball); }; } while (nextball > -1); if (ct.FreeSlots > 0){ cm.PartialTickets.addElement(ct); } else { cm.FullTickets.addElement(ct); }; Focus = cm.getNextUncovered(Focus); }; mergepartials(); cleanup(); mergepartials(); }; void startwithdisjointtickets(int displacement){ int [] ticketbuilder = new int[7]; for (int i=displacement;i 0){ cm.PartialTickets.addElement(cm.FullTickets.elementAt(i)); cm.FullTickets.removeElementAt(i--); }; }; for (int i=0;i< cm.PartialTickets.size();i++){ ( (Ticket) cm.PartialTickets.elementAt(i)).removeRedundantBalls(); if (( (Ticket) cm.PartialTickets.elementAt(i)).FreeSlots == 7){ cm.PartialTickets.removeElementAt(i--); }; }; }; void mergepartials(){ int i=0; while (i< cm.PartialTickets.size()){ int j=i+1; while (j < cm.PartialTickets.size()){ if (((Ticket) cm.PartialTickets.elementAt(i)).canMergeSet( ((Ticket) cm.PartialTickets.elementAt(j)))){ ((Ticket) cm.PartialTickets.elementAt(i)).mergeSet( ((Ticket) cm.PartialTickets.elementAt(j))); cm.PartialTickets.removeElementAt(j); } else { j++; }; }; if (((Ticket) cm.PartialTickets.elementAt(i)).FreeSlots == 0){ cm.FullTickets.addElement(cm.PartialTickets.elementAt(i)); cm.PartialTickets.removeElementAt(i); } else { i++; }; }; }; public static void main(String args[]){ int N = Integer.parseInt(args[0]); int whichmethod = -1; if (args.length > 1){ whichmethod = Integer.parseInt(args[1]); }; TuranProblem tp = new TuranProblem(N); tp.basicmethod(whichmethod); tp.mergepartials(); tp.cleanup(); tp.mergepartials(); int [] outscore = tp.cm.getTicketCount(); System.out.println( "case N=" + N + ": " + (outscore[0] + outscore[1] + outscore[2]) + " full tickets, " + outscore[3] + " fourples, " + outscore[4] + " threeples."); }; // end main } /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ class CoverManager{ int HowManyBalls; Vector FullTickets; Vector PartialTickets; int[] TicketsPerBall; byte[][][] TriplesCovered; int[] getTicketCount(){ //output is number with 7,6,5,4,3 int [] output = new int[5]; output[0] = FullTickets.size(); for (int i=0; i otot){ return false; }; //if here, counts are equal. now just compare threeples and fourples mtot = mcount[3]+mcount[4]; otot = ocount[3]+ocount[4]; if (mtot > otot){ return true; }; if (mtot < otot){ return false; }; //if here, threeples + fourples are equal. this one is better only //if it has fewer fourples. else it's same or worse BUT SAME IS OK! if (mcount[3] <= ocount[3]){ return true; }; return false; } boolean isCovered(int i, int j, int k){ int [] indo = convertToIndexForm(i,j,k); return (TriplesCovered[indo[0]][indo[1]][indo[2]] > 0); }; boolean isCovered( int[] threeguys){ return isCovered(threeguys[0],threeguys[1],threeguys[2]); }; boolean isRedundant(int i, int j, int k){ int [] indo = convertToIndexForm(i,j,k); return (TriplesCovered[indo[0]][indo[1]][indo[2]] > 1); }; void addToCover(int i, int j, int k){ int [] indo = convertToIndexForm(i,j,k); TriplesCovered[indo[0]][indo[1]][indo[2]]++; }; void removeFromCover(int i, int j, int k){ int [] indo = convertToIndexForm(i,j,k); TriplesCovered[indo[0]][indo[1]][indo[2]]--; }; int[] convertToIndexForm(int i, int j, int k){ //we do assume i,j,k are sorted! int[] output = new int[3]; output[0]=i; output[1]=j-i-1; output[2]=k-j-1; return output; }; int[] convertFromIndexForm(int[] index){ int [] output = new int[3]; output[0]=index[0]; output[1]=index[1]+index[0]+1; output[2]=index[2]+index[1]+index[0]+2; return output; }; int[] getNextUncovered(int i, int j, int k){ for (int [] place = convertToIndexForm(i,j,k); place[0]!=-1; place = nextPlace(place)){ if (TriplesCovered[place[0]][place[1]][place[2]]==0){ int [] output = convertFromIndexForm(place); return output; }; }; int [] output = {-1,-1,-1}; return output; }; int [] getNextUncovered(int[] arrayform){ return getNextUncovered( arrayform[0],arrayform[1], arrayform[2]); }; int [] nextPlace(int [] place){ place[2]++; if (place[2] == TriplesCovered[place[0]][place[1]].length){ place[2] = 0; place[1]++; if (place[1] == TriplesCovered[place[0]].length){ place[1] = 0; place[0]++; if (place[0] == TriplesCovered.length){ place[0]=-1; }; }; }; return place; }; Vector sortBallsByFrequency(){ Vector BallList = new Vector(HowManyBalls); BallList.addElement(new Integer(0)); for (int i=1;i