Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 18880 | Accepted: 6549 |
Description
Input
Output
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
}