传送门:poj1011
题意:给你一些长度不同的棍子,让你把他们拼成长度相同的新棍子,问最小长度是多少
枚举所有可能长度,dfs并不难写,重点是剪枝,将棍子长度按从大到小排序后从前往后dfs,这里有一点是如果把一个棍子当要组成的新棍子的第一根都无法组合成功,那么放在后面更不可能和其他棍子组成想要的长度了,可以这样考虑:如果这个棍子在后面那么多棍子都还没用的情况下都和它们组成不了想要的长度,等到其他棍子都用的差不多了就更组不成了。所以如果某个棍子和后面的组合失败,这时候要分两种情况,如果它是组成新棍子的第一根,那么就直接返回,如果不是第一根,那么就要直接跳过所有相同长度的棍子再用其他的进行组合。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
int n,sum=0,num,len=0;
int L[65],book[65];
using namespace std;
int cmp(int a,int b)
{
return a>b;
}
int dfs(int cnt,int l,int id)//传参为已组成的新棍子的数量、当前已组成的长度、上次使用的棍子序号。
{
if(cnt==num)
return 1;
for(int i=id;i<n;i++)
{
if(!book[i])
{
if(L[i]+l==len)
{
book[i]=1;
if(dfs(cnt+1,0,0))
return 1;
book[i]=0;
return 0;
}
else if(L[i]+l<len)
{
book[i]=1;
if(dfs(cnt,l+L[i],i+1))
return 1;
book[i]=0;
if(l==0)//重要剪枝
return 0;
while(L[i]==L[i+1])
i++;
}
}
}
return 0;
}
int main()
{
while(scanf("%d",&n)&&n)
{
sum=0;
memset(book,0,sizeof(book));
for(int i=0;i<n;i++)
{
scanf("%d",&L[i]);
sum+=L[i];
}
sort(L,L+n,cmp);
for(int i=L[0];i<=sum;i++)//枚举新棍子所有可能长度
{
if(sum%i)
continue;
num=sum/i;
len=i;
if(dfs(0,0,0))
{
printf("%d\n",i);
break;
}
}
}
return 0;
}
2017/03/08
今天又做了一遍这个题,这次终于在没看任何题解的情况下把他剪出来了,特兴奋,忙活这么长时间自己也算是有进步吧,虽然还有小剪枝没想到,但是影响不大,16ms水过。
第二次代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
#define ll long long
#define pi acos(-1)
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef pair<int,int>P;
const int MAXN=100010;
bool cmp(int a,int b)
{
return a>b;
}
int num[70],book[70];
int sum_len,max_len,aim,N;
bool flag;
void dfs(int cnt,int len,int k)
{
if(flag)return ;
if(cnt==sum_len/aim)
{
flag=1;
return ;
}
for(int i=k;i<N;i++)
{
if(book[i])continue;
if(len+num[i]==aim)
{
book[i]=1;
dfs(cnt+1,0,0);
book[i]=0;
return ;
}
else
{
if(len+num[i]>aim)continue;
book[i]=1;
dfs(cnt,len+num[i],i+1);
book[i]=0;
if(flag||len==0)return ;//这里没想出如果len!=0的话就把所有长度相同的棍子跳过了
}
}
}
int main()
{
while(cin>>N)
{
if(!N)break;
sum_len=0;
max_len=0;
flag=0;
for(int i=0;i<N;i++)
{
scanf("%d",num+i);
sum_len+=num[i];
max_len=max(num[i],max_len);
}
sort(num,num+N,cmp);
for(int i=max_len;i<=sum_len;i++)
{
if(sum_len%i)continue;
memset(book,0,sizeof(book));
aim=i;
dfs(0,0,0);
if(flag)
{
cout<<aim<<endl;
break;
}
}
}
return 0;
}