poj_1020 anniversary cake

求給定的n(1<=n<=16)個正整數邊長的小正方形(每個邊長<=10)能否恰好無重疊拼成一個邊長爲s的大正方形。

思路和方法:這道題不可以用貪心算法,有特殊的情況會覆蓋不到。

思路:類似於歐羅斯方塊,每次選一個方塊放到最低點。
數據結構解釋:
struct piece{
    int size;//邊長
    int num;//數量
    int remine;//剩餘 
} //存儲每個蛋糕碎片的信息
struct piece pieces[];//蛋糕碎片的數組


struct bottom{
    int height;//這段底部的高度
    int length;//這段底部的長度
} //底部
struct bottom bottoms[];//由已放正方形組成的底部 

bool insert(struct piece pieces[], struct bottom bottoms[]){
    ok = false;
    for(遍歷pieces[]中剩餘的piece){
        if(最低點可以放入){
            for( 選擇放入位置 ){
                if(可以放入){
                    在指定位置放置piece
                    修訂bottoms[] 
                    if(填滿)
                        return true; 
                    ok = insert(); 
                    if( ok )
                        return true;
                } 
            } 
        }       
    }
    return ok;


struct piece{
    int size;//邊長
    int num;//數量
    int remine;//剩餘 
};
struct bottom{
    int height;
    int length;
    struct bottom *nextptr;
};  

int piece_type = 0;
int cake;

int empty(struct piece pieces[]){
    int i;
    for( i=0; i<piece_type; ++i ){
        if(pieces[i].remine>0)
            return 0;
    }
    return 1;
}

int insert(struct piece pieces[], struct bottom *bottoms){
    struct piece pieces_[20];
    struct bottom *bottoms_, *ptr, *ptr_, *b_index, *b_index_, *pre_index, *pre_index_, *tptr;
    int ok = 0;
    int i,j,k,lowest,width;
    for( i=0; i<piece_type; ++i ){
        if(pieces[i].remine>0){
            //printf("try: %d ",pieces[i].size);//debugggggggggggggggggggggggggg
            //找到最低點
            //printf("[%d,%d]-",bottoms->height,bottoms->length);//debugggggggggggggggggggggggggg
            for(ptr = b_index = bottoms,lowest=bottoms->height,pre_index = NULL; ptr->nextptr; ptr = ptr->nextptr){
                //printf("[%d,%d]-",ptr->nextptr->height,ptr->nextptr->length);//debugggggggggggggggggggggggggg  
                if(ptr->nextptr->height<lowest){
                    b_index = ptr->nextptr;
                    pre_index = ptr;
                    lowest = ptr->nextptr->height;
                }
            }
            //printf("   height:%d   length:%d\n",b_index->height,b_index->length);//system("pause");//debugggggggggggggggggggggggggg
            for(j=0; j<b_index->length; ++j){//選擇放入位置
                if( b_index->length - j >= pieces[i].size && cake - b_index->height >= pieces[i].size ){//選擇的位置可以放下蛋糕碎片 
                    //複製bottoms[] pieces[]
                    for( k=0; k<piece_type; ++k ){
                        pieces_[k].size = pieces[k].size;
                        pieces_[k].num = pieces[k].num;
                        pieces_[k].remine = pieces[k].remine;
                    }
                    for( ptr = bottoms, pre_index_ = b_index_ = ptr_ = bottoms_ = tptr = NULL; ptr; ptr = ptr->nextptr ){
                        ptr_ = (struct bottom *)malloc(sizeof(struct bottom));
                        ptr_->height = ptr->height;
                        ptr_->length = ptr->length;
                        ptr_->nextptr = NULL;
                        if( bottoms_ == NULL ) tptr = bottoms_ = ptr_;//處理頭指針 
                        else{
                            tptr ->nextptr = ptr_; tptr = ptr_;
                        }
                        //複製b_index 和 pre_index 
                        if(ptr == b_index){ b_index_ = ptr_; }
                        if(ptr == pre_index){ pre_index_ = ptr_; }
                    }
                    
                    
                    --pieces_[i].remine;//在指定位置放置piece

                    //修訂bottoms
                    if(j==0){
                        b_index_->height = pieces_[i].size + b_index_->height;
                        width = b_index_->length;
                        b_index_->length = pieces_[i].size;
                        if( pre_index_ && pre_index_->height == b_index_->height ){//如果和左邊的bottom連成一片
                            pre_index_->length = pre_index_->length + b_index_->length;
                            tptr = b_index_;
                            b_index_ = pre_index_;
                            b_index_->nextptr = tptr->nextptr;
                            free(tptr);
                        } 
                        if( width - pieces_[i].size != 0 ){//放入後還留有空隙 
                            ptr = (struct bottom *)malloc(sizeof(struct bottom));
                            ptr->height = b_index_->height - pieces_[i].size;
                            ptr->length = width - pieces_[i].size;
                            ptr->nextptr = b_index_->nextptr;
                            b_index_->nextptr = ptr;
                        } else{
                            if( b_index_->nextptr && b_index_->height == b_index_->nextptr->height ){//和右邊連成一片 
                                b_index_->length =  b_index_->length + b_index_->nextptr->length;
                                tptr = b_index_->nextptr;
                                b_index_->nextptr = tptr->nextptr;
                                free(tptr);
                            }
                        }
                        
                    } else{
                        width = b_index_->length;
                        b_index_->length = j;
                        ptr = (struct bottom *)malloc(sizeof(struct bottom));
                        ptr->height = b_index_->height + pieces_[i].size;
                        ptr->length = pieces_[i].size;
                        ptr->nextptr = b_index_->nextptr;
                        b_index_->nextptr = ptr;
                        if( width - pieces_[i].size -j != 0 ){
                            ptr = (struct bottom *)malloc(sizeof(struct bottom));
                            ptr->height = b_index_->height;
                            ptr->length = width - pieces_[i].size - j;
                            ptr->nextptr = b_index_->nextptr->nextptr;
                            b_index_->nextptr->nextptr = ptr;
                        } else{
                            if(b_index_->nextptr->nextptr && b_index_->nextptr->height == b_index_->nextptr->nextptr->height){//和右邊連成一片
                                b_index_->nextptr->length = b_index_->nextptr->length + b_index_->nextptr->nextptr->length;
                                tptr = b_index_->nextptr->nextptr;
                                b_index_->nextptr->nextptr = tptr->nextptr;
                                free(tptr); 
                            }
                        }
                        
                    }
                    
                    
                    if( bottoms_->nextptr == NULL && bottoms_->height == cake && empty(pieces_))//如果裝滿
                        return 1; 
                    //遞歸 
                    ok = insert(pieces_, bottoms_); 
                    if( ok )//找到一個可以的分支 
                        return 1;
                } else{
                    break;
                } 
            } 

        }
    }
    return ok;
}

int main(){
    int n,m,i,j,k,find,temp;
    
    struct piece pieces[20];
    struct bottom *bottoms;
    
    scanf("%d",&n);
    for( i=0; i<n; ++i ){
        for(i=0;i<20;++i){ pieces[i].num = pieces[i].remine = 0; }//初始化  
        
        scanf("%d %d",&cake, &m);//存放蛋糕的邊長,碎片的塊數
        piece_type = 0;//初始化碎片種類 
        for( j=0; j<m; ++j ){//寫入碎片表 
            scanf("%d",&temp);
            find = 0;
            for( k=0; k<piece_type; ++k ){ 
                if( pieces[k].size == temp ){
                    find = 1;
                    ++pieces[k].num; 
                    ++pieces[k].remine;  
                    break;
                }
            }
            if(find == 0){
                pieces[piece_type].num = pieces[piece_type].remine = 1;
                pieces[piece_type].size = temp;
                ++piece_type;
            } 
        }
        bottoms = (struct bottom *)malloc(sizeof(struct bottom));
        bottoms->height = 0; bottoms->length = cake;//初始化bottoms
        bottoms->nextptr = NULL;
        if(insert(pieces,bottoms))  printf("ok\n");
        else  printf("failed\n"); 
        system("pause");
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章