Tävlingsprogrammering/Uppgifter/Dela tårtan

Från Wikibooks


Dela tårtan

Du får en 5x5 matris som föreställer en tårta indelad i 25 områden. Varje område har en bokstav (vald bland A-E) som markerar dess "innehåll" (aprikos, banan, chokladbit, druva eller extragrädde). Dela tårtan i fem delar så att alla delar är sammanhängande, lika stora och innehåller samma saker.

Indata

5 rader vardera innehållande 5 tecken, valda bland A-E (men alla behöver inte förekomma). Antalet bokstäver av ett visst slag är alltid delbart med fem.

Utdata

Programmet ska skriva ut 5 rader med 5 tecken (valda bland 1-5), föreställande samma tårta som i indatan men där varje siffra nu motsvarar en tårtbit. Du kan räkna med att det alltid finns minst en lösning och det spelar ingen roll hur du numrerar tårtbitarna.

Exempel: Indata

CBCAB
ABCAA
ACACB
ACACA
BCCCA

Exempel: Utdata

11114
12444
22245
32355
33355

Exempel: Förklaring

Varje tårtbit är sammanhängande och innehåller samma saker: två aprikoser, en banan och två chokladbitar.

Lösning[redigera]

Vid första anblick kan uppgiften se svår ut och att en lösning som rekurserar och testar "alla möjliga fall" skulle ta alldeles för lång tid på sig. Faktum är att om man alltid kontrollerar att en bit "passar" innan man lägger dit den, dvs. att man har ringat in precis så många A,B,C,D,E som ska vara med, kommer det gå väldigt snabbt att komma fram till en lösning. Det är bra att man bara behöver skriva ut den första lösningen man kommer fram till, och att inte uppgiften var t.ex. Hur många sätt finns det att dela in tårtan på? Det finns nämligen oftast väldigt många sätt att dela in tårtan på.

#include <iostream>
#include <cstdio>
using namespace std;

char tarta[5][5][2];//första nivån är tårtan, 2:ra - bitarna vi ska dela den i.
short antalBokst[5];//antal A:n, B:n osv

struct bit
{
  short antalBitar;
  pair<short,short> allaBitar [5];//alla bitarna.
  char siffra;//kanske inte
  short behovs[5];//antal A:n, B:n... som behövs.
  bit(char s,short x, short y)
  {
    antalBitar=1;
    siffra=s;
    allaBitar[0]=make_pair(x,y);
    for(int i=0;i<5;i++)
      behovs[i]=antalBokst[i];
    behovs[tarta[x][y][0]-'A']-=1;
  }
void  addRuta(short x,short y)
  {
    allaBitar[antalBitar]=make_pair(x,y);
    antalBitar++;
    behovs[tarta[x][y][0]-'A']-=1;
    tarta[x][y][1]=siffra;
  }
  void  deleteRuta( )
  {
    short x = allaBitar[antalBitar-1].first;
    short y = allaBitar[antalBitar-1].second;
    antalBitar--;
    behovs[tarta[x][y][0]-'A']+=1;
    tarta[x][y][1]=0;
  }
};

bool hittaBit(bit B)
{
  
  //hittar en ny bit. Kolla hur mycket saker som finns, testar sätta en ny ruta runt varje existerande.
  if(B.antalBitar==5)
    {
      //försök hitta ny bit:
      for(int i=0;i<5;i++)
	for(int j=0;j<5;j++)
	  if(tarta[i][j][1]==0){
	    tarta[i][j][1]=B.siffra+1;
	    if(! hittaBit(bit(B.siffra+1,i,j)))
	      {
		tarta[i][j][1]=0;
		return false;
	      }
	    else
	      return true;
	    
	  }
      return true; //true;//om det inte finns nårga bitar kvar är vi klara :)
    }
  
  for(int i=0;i<B.antalBitar;i++)
    {
      int x=B.allaBitar[i].first;
      int y=B.allaBitar[i].second;
      int yleft=y-1;
      if(yleft>=0 && B.behovs[tarta[x][yleft][0]-'A']>0 && tarta[x][yleft][1]==0)
	{
	  B.addRuta(x,yleft);
	  if(!hittaBit(B))
	    B.deleteRuta();
	  else return true;
	}
     }
  for(int i=0;i<B.antalBitar;i++)
    {
      int x=B.allaBitar[i].first;
      int y=B.allaBitar[i].second;
      int xup=x-1;
      if(xup>=0 && B.behovs[tarta[xup][y][0]-'A']>0 && tarta[xup][y][1]==0)
	{
	  B.addRuta(xup,y);
	  if(!hittaBit(B))
	    B.deleteRuta();
	  else return true;
	}
    }

  for(int i=0;i<B.antalBitar;i++)
    {
      int x=B.allaBitar[i].first;
      int y=B.allaBitar[i].second;
      int xdown=x+1;
      if(xdown<=4 && B.behovs[tarta[xdown][y][0]-'A']>0 && tarta[xdown][y][1]==0)
	{
	  B.addRuta(xdown,y);
	  if(!hittaBit(B))
	    B.deleteRuta();
	  else return true;
	}
     }
  for(int i=0;i<B.antalBitar;i++)
    {
      int x=B.allaBitar[i].first;
      int y=B.allaBitar[i].second;
      int yright=y+1;
      if(yright<=4 && B.behovs[tarta[x][yright][0]-'A']>0 && tarta[x][yright][1]==0)
	{
	  B.addRuta(x,yright);
	  if(!hittaBit(B))
	    B.deleteRuta();
	  else return true;
	}
     }


  B.deleteRuta();
  return false;
}

  
void zolve(char bit_nr)
{
  //hitta en lagom pajbit, kapa den, zolva resten, testa en annan tårtbit osv
  //ta 1:a icketomma rutan, kolla runt den
  tarta[0][0][1]='1';
  hittaBit(bit('1',0,0));
}


int main()
{
  for(int i=0;i<5;i++)antalBokst[i]=0;
  
  //läsa indata och zolve(1):a
  for(int i=0;i<5;i++)
    for(int j=0;j<5;j++)
      {
	cin>>tarta[i][j][0];
	antalBokst[tarta[i][j][0]-'A']++;
	tarta[i][j][1]=0;
      }
  //yeah! nu har vi en tårta! mmm... tårta...

  for(int i=0;i<5;i++)
    antalBokst[i]/=5; //nu vet vi hur många det ska va i varje bit
  
  zolve('1');
  
  //skriv ut tårta!
  for(int i=0;i<5;i++){
    for(int j=0;j<5;j++)
      printf("%c", tarta[i][j][1]);
    cout<<endl;
  }
}