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
}


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