PKU 1020 Anniversary Cake(Dfs)

來源:互聯網
上載者:User

一道簡單的搜尋題,我卻做了兩天,真是失敗,從剛開始,沒有思路,到想到方法,再到如何?,從N次wrong後,到TLE,再剪枝最佳化,最後Accept,可謂一路辛苦,其中也多虧大牛的提示。 
      題意是把一個大蛋糕(邊長為E),能否切成給定s(s<15)個邊長為Ei(1=<Ei<=10)的小蛋糕,所有的蛋糕都是正方形.題目的規模不是很多,應該是深搜來拼,剛開始一點頭緒也沒有,以前只搜過點。
     1.儲存狀態很重要,這是遇到的第一個問題,想法是用一個矩形來儲存,用一個表示列的數組d[i](這個剛開始沒想到),d[i]表示第i列沒填蛋糕的行數。
     2.搜尋的策略,很容易想到可以從矩陣的左上方開始填,每次按列從左邊向右填,左邊的填完了才能天右邊的,顯然這樣是正確的。
     3.最佳化與剪枝,首先,所有小蛋糕的面積和不等於要拼的蛋糕的面積,則沒必要填。如果直接從左上方填這樣效率很低的,可以每次按蛋糕從大到小開始填,可以想到這樣很高效的。當時根據以上兩點寫了後,調試出正確答案後,提交依然逾時,這樣,如果不可以不可以拼成的話,就會執行 piece!次,看了discuss之後,才發現如果該大小的蛋糕填不進去,則其他相同大小的蛋糕就沒有必要所了,回溯後,原先大小的蛋糕也沒必要填,剛開始,我是用一個數組存這些切成的蛋糕的邊長,然後對其遞減排序,每次按數組下標填入,那麼如果該大小的蛋糕放不下,則下標就應該跳rec[](表示該大小的蛋糕數),但這樣不好控制,調試了很長時間都沒成功。其實很簡單,沒必要排序,每次選最大的蛋糕,因為蛋糕最大是10,所以從10開始選,一直遞減,看有沒有該大小的蛋糕,能不能放入,如果放不下則選擇比其小的蛋糕即可,否則,該蛋糕的數目減一,修改該矩形,搜尋下一塊蛋糕,如果該拼法行不通,則回溯。
這其中,反映出我很差的代碼能力,以及對深度搜尋認識的薄弱,以及對問題認識不夠深刻,不夠全面,以後這方面要努力了!加油!

 

Source Code

Problem: 1020  User: zhouxc
Memory: 200K  Time: 47MS
Language: C++  Result: Accepted

 

#include "iostream"

using namespace std;

int test,cake,piece;
int p[20],d[50],rec[20];
bool wasted,cpt;
int Find_Min()
{
       //返回最左列第一個有插完的一列的行號,以後每次會從該列插入
蛋糕,這一列前面的列都插完了,而後面的還沒插
        for(int i=0;i<cake;i++)         
        {    
                if(d[i]!=0)
                    return i;
        }
        return -1;//  返回-1表示每一列都插完了,則可以正好分配
}                   
               
//  dfs切每一塊蛋糕,其中cunt表示切了的蛋糕數
bool Cake_dfs(int cunt)   {
    
   // 最左邊未填慢的列,下一塊蛋糕將要開始從該列緊挨著已填的填入
           int rr=Find_Min();
         // printf("%d %d/n",rr,cunt);  
         if(rr==-1)     //表示正好填好
              return true;
        //每次填時嘗試取最大的蛋糕         
         else                
         {      //size表示蛋糕的大小,因為蛋糕最大不超過10
               for(int size=10;size>0;size--)
               {
                 
                   if(rec[size]) //如果存在該大小的蛋糕
                   {     
                           cpt=true;  
                           //判斷該大小的蛋糕是否可填入
                           for(int j=rr;j<size+rr;j++)
                           {
                               if(d[j]<size)
                               {     
                                     cpt=false;
                                     break;
                               } 
                            } 
                            if(cpt)          
                            {
                                 //把該大小的蛋糕填入,並修改填入後的d值
                                 for(int i=rr;i<size+rr;i++)
                                         d[i]-=size;
                                //該大小的蛋糕數減一
                                 rec[size]--;
                                //搜尋填入下一塊蛋糕
                                 if(Cake_dfs(cunt+1))
                                    return true;
                                 //當該方案行不通時回溯,嘗試另一種填法  
                                 rec[size]++;
                                 for(int i=rr;i<size+rr;i++)
                                        d[i]+=size; 
                            }               
                     }
                }
                   
            } 
            return false; 
                 
}        
        
int main()
{
         scanf("%d",&test);
         while(test--)
         {
               int result=0;c=0;
               scanf("%d%d",&cake,&piece);
               memset(rec,0,sizeof(rec));
               for(int i=0;i<piece;i++)
               {
                      scanf("%d",&p);
                      result+=p*p;
                      rec[p]++;  //邊長為p的蛋糕的數
               }
            //初始化,d[i]表示第i列,已填入蛋糕的行數,剛開始都沒填
               for(int i=0;i<cake;i++)      
                   d[i]=cake;
                wasted=true;
              //當所有的的蛋糕的面積和等於要拼成的蛋糕面積時,開始拼,否則一定不能拼成    
               if(result==cake*cake)
                   wasted=!Cake_dfs(0);
               if(!wasted)
                     puts("KHOOOOB!");
               else
                     puts("HUTUTU!");    
         }   
         return 0;
}

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.