洛谷P1120 小木棍 [数据加强版](剪枝技巧!)

题目链接

P1120 小木棍 [数据加强版]

参考自:

https://www.luogu.org/blog/user30688/solution-p1120

解题思路:

这题关键在于剪枝。
(1)逆序排列整个序列,从最大的值往回搜
(2)dfs每次从当前点 n o w now 开始搜,而不是每次从最开始的点 a [ 1 ] a[1] 开始搜
(3)在正向的搜索过程中,如果当前积累的长度 n u m num 与平均值 a v e r aver 的差比整个序列的最小值还小,那么一定不能凑成一组, r e t u r n return
(4)技巧部分还在回溯过程:回溯过程中如果找到一组(即 n u m + a [ i ] = = a v e r num+a[i]==aver )或者回到上一层开始的地方(即 n u m = = 0 num==0 ),表示当前组不符合, r e t u r n return
(5)其次,回溯过程中,如果有很多重复的数字,直接跳过(即 w h i l e ( a [ i ] = = a [ i + 1 ] ) i + + ; while(a[i]==a[i+1]) \quad i++; )。

#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[70],vis[70];
int sum=0,maxa=-1,aver=0,cnt=0;
int n,flag=0,m=0;
bool cmp(int x,int y){
	return x>y;//逆序 
}
void dfs(int step,int num,int now){//从now开始,而不是每次从1开始,节省时间 
//step表示搜索的组数,num表示每一组积累的长度,now表示现在正遍历的点
//	printf("%d %d\n",step,num);
    if(step==cnt||flag){
    	printf("%d\n",aver),exit(0);//退出 
        flag=1;
        return;
    }
    if(num==aver){
        dfs(step+1,0,1);//从头开始 
        return;
    }
    if(aver-num<a[n])  return;//这步是说明在前面的两步判断之后,如果我们的平均值减去这个num的值
                               //比整个序列的最小值还小,那一定不能再凑成新的一组了。 
    for(int i=now;i<=n;i++){
        if(!vis[i]&& num+a[i]<=aver){//除了保证i没有被访问过,还要保证num+当前的a[i]小于平均值,才能进入下一步的dfs 
        	vis[i]=1;
            dfs(step,num+a[i],i+1);//开始下一步 
			vis[i]=0;             //回溯过程的处理非常关键 
			if(num+a[i]==aver) return;//回溯找到一组,不可行
			if(num==0)  return;//回溯到上一层最开始的地方,不可行 
            while(a[i]==a[i+1]) i++;//回溯时消除重复的值 (1)
        }
    }
}
int main(int argc, char** argv) {
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        if(x>50){
            continue;
        }
        a[++m]=x;
        if(a[m]>maxa) maxa=a[m];//最大值 
        sum+=a[m];
    }
    n=m;
    sort(a+1,a+n+1,cmp);//逆序排列,从最大值往回找 
    
    for(int i=maxa;i<=sum;i++){
        if(sum%i==0){
            aver=i,cnt=sum/i;
            dfs(0,0,1);
            if(flag) break;
        }
    }
    printf("%d\n",aver);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhuixun_/article/details/82945508