poj2362(小木棍問題的逆過程)

Square
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 18880   Accepted: 6549

Description

Given a set of sticks of various lengths, is it possible to join them end-to-end to form a square?

Input

The first line of input contains N, the number of test cases. Each test case begins with an integer 4 <= M <= 20, the number of sticks. M integers follow; each gives the length of a stick - an integer between 1 and 10,000.

Output

For each case, output a line containing "yes" if is is possible to form a square; otherwise output "no".

Sample Input

3
4 1 1 1 1
5 10 20 30 40 50
8 1 7 2 6 4 4 3 5

Sample Output

yes
no
yes

題目描述:

給出M根小木棍,問是否能拼成一個正方形。相當於把小木棍復原成4根等長的大木棍,若能,輸出Yes,否則輸出No。

解題思路:

回溯法,即深搜,再加一些剪枝,具體看代碼註釋。

#include<iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;

int M, side;
int stick[21];//各個小木棍
bool mark[21];//標記數組,記錄小木棍是否用過

int cmp(const void *a,const void *b);
int dfs(int num,int len);

int main()
{
    int i, N;
    cin>>N;
    while(N --)
    {
        int sum = 0;
        memset(mark,0,sizeof(mark));
        cin >> M;
        for(i=0; i<M; i++)
        {
            cin >> stick[i];
            sum += stick[i];//sum是所有小木棍長度的總和
        }
        side = sum / 4;//side是拼成的正方形的邊長

        qsort(stick,M,sizeof(stick[0]),cmp);//把所有小木棍長度排序,降序排

        if(stick[0] > side)//剪枝1,如果最長木棍長度大於正方形邊長,則肯定無法拼成正方形
        {
            cout << "No" <<endl;
            continue;
        }
        if(dfs(0,0))
        {
            cout << "Yes" << endl;
        }
        else
        {
            cout << "No" << endl;
        }
    }
    return 0;
}

int cmp(const void *a,const void *b)
{
    int *p1, *p2;
    p1 = (int *) a;
    p2 = (int *) b;
    return *p2 - *p1;
}

int dfs(int num,int len)//num表示已拼成的邊數,len表示當前正在拼的木棍的長度
{
    if(num == 3)//剪枝2,如果已經拼成三條邊,則成功,因爲所有木棍總和是邊長的四倍,最後一條邊一定可以由剩下的木棍拼成
    {
        return 1;//出口一,拼成功,返回1
    }
    for(int i=0; i<M; i++)//遍歷所有小木棍
    {
        if(mark[i] == 0)//若沒有標記過
        {
            if(len + stick[i] < side)//如果當前長度加當前木棍長度小於邊長
            {
                len += stick[i];
                mark[i] = 1;
                if(dfs(num,len))//繼續向下深搜
                {
                    return 1;
                }
            }
            else if(len + stick[i] == side)//如果當前長度加當前木棍長度等於邊長
            {
                len = 0;
                mark[i] = 1;
                if(dfs(num+1,len))//num加一,深搜拼下一條邊
                {
                    return 1;
                }
            }
        }
    }
    return 0;//沒有從出口一出去,說明不能拼成,返回0
}


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