CJOJ1642 小木棍

首先for一遍看拼成多长的木棍

然后DFS

以前你已经拼好了sum根棍子

这根棍子你已经拼了len长度

从1到50枚一遍,看放多长的木棍,然后接着搜

恩下面给出裸搜代码,30分到手

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#define MAX 50
#define rg register
using namespace std;
int n,N[MAX+1],Nlen,yes,Max=0,Sum=0;
void dfs(int sum,int len){
//已经凑好了sum根,最后一根长度len
	if(len==Nlen)sum++,len=0;
	if(sum==Sum/Nlen){yes=1;return;}
	for(rg int i=Nlen-len;i;i--)
	    if(N[i]){
	    	N[i]--;
	    	dfs(sum,len+i);
	    	N[i]++;
		}
}
int main(){
	rg int data;
	scanf("%d",&n);
	for(rg int i=1;i<=n;i++){
	    scanf("%d",&data);
	    if(data>MAX)--i,--n;
	    else Max=max(Max,data),Sum+=data,N[data]++;
	}
	for(rg int i=Max;i<=Sum;i++)
	    if(!(Sum%i)){
	    	Nlen=i;
	    	dfs(0,0);
	    	if(yes){printf("%d\n",i);break;} 
		}
	return 0;
}
/*
9 
5 2 1 5 2 1 5 2 1
*/
显然30分无法让利欲熏心的你满足

于是我开始想怎么剪

题目所给的木棍称作小木棍,要拼接的木棍成为大木棍

有一个傻逼剪枝:如果dfs之后yes=1了,直接跳出循环

然后,对于每根大木棍,可以将拼接的小木棍sort一遍,所以可以从大到小放棍子(自己想为什么不能从小到大)

给出剪枝后的代码,加上这两个剪枝以后有80分了

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#define MAX 50
#define rg register
using namespace std;
int n,N[MAX+1],Nlen,yes,Max=0,Sum=0;
void dfs(int sum,int len,int last){
//已经凑好了sum根,最后一根长度len,前一个放last 
	if(len==Nlen)sum++,len=0,last=MAX;
	if(sum==Sum/Nlen){yes=1;return;}
	for(rg int i=min(last,Nlen-len);i;i--)
	    if(N[i]){
	    	N[i]--;
	    	dfs(sum,len+i,i);
	    	if(yes)return;
	    	N[i]++;
		}
}
int main(){
	rg int data;
	scanf("%d",&n);
	for(rg int i=1;i<=n;i++){
	    scanf("%d",&data);
	    if(data>MAX)--i,--n;
	    else Max=max(Max,data),Sum+=data,N[data]++;
	}
	for(rg int i=Max;i<=Sum;i++)
	    if(!(Sum%i)){
	    	Nlen=i;
	    	dfs(0,0,MAX);
	    	if(yes){printf("%d\n",i);break;} 
		}
	return 0;
}
/*
9 
5 2 1 5 2 1 5 2 1
*/
那么如何AC?

如果一根大木棍的len==0,且dfs完第一遍之后没有答案,那么之后的dfs肯定没有答案,这很科学

加上愉快AC

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#define MAX 50
#define rg register
using namespace std;
int n,N[MAX+1],Nlen,rest,yes,Max=0,Sum=0;
void dfs(int sum,int len,int last){
//已经凑好了sum根,最后一根长度len,前一个放last 
	if(len==Nlen)sum++,len=0,last=MAX;
	if(rest==1){yes=1;return;}
	for(rg int i=min(last,Nlen-len);i;i--)
	    if(N[i]){
	    	N[i]--,rest--;
	    	dfs(sum,len+i,i);
	    	if(yes)return;
	    	N[i]++,rest++;
	    	if(!len)return;
	        }
}
int main(){
	rg int data;
	scanf("%d",&n);
	for(rg int i=1;i<=n;i++){
	    scanf("%d",&data);
	    if(data>MAX)--i,--n;
	    else Max=max(Max,data),Sum+=data,N[data]++;
	}
	for(rg int i=Max;i<=Sum;i++)
	    if(!(Sum%i)){
	    	Nlen=i,rest=n;
	    	dfs(0,0,MAX);
	    	if(yes){printf("%d\n",i);break;} 
		}
	return 0;
}
/*
9 
5 2 1 5 2 1 5 2 1
*/




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值