• [算进] 小木棍


    Problem

    ACwing 题目地址

    洛谷 题目地址

    Before

    做完16*16的数独后感觉这些搜索题都是小清新。

    但是小木棍这题还是烦了我特别久,因此来写篇题解吧,总结一下。

    Sulotion

    这题无非就是两个剪枝,优化搜索顺序 + 去掉等效状态

    优化搜索顺序

    • 1.很明显,从大到小排,这样未来可选择的空间更少,搜索树更小。

    去掉等效状态

    • 1.假设一条木棍是由 1,3,6 拼接成的,1,6,3 和 3,1,6 这些顺序就是等效状态。我们只要保证每根大木棍内部编号顺序递增,那么就可以剪掉这些等效状态。

    • 2.假设用长度为 5 的木棍拼接失败,那么就要跳过所以长度为 5 的木棍。所以跳过长度相等的并且失败了的木棍

    • 3.如果第一个木棍拼接失败,那么可以剪掉这个分支。反证法:条件:第一个木棍拼接失败。假设这个这个分支可以成功,那么将第一根木棍所在的那条大木棍放在第一个木棍这里,就可以拼接成功,条件不成立,故原命题成立。如果最后一个木棍拼接失败,那么可以剪掉这个分支,因为最后一个木棍是恰好可以拼好这个大木棍的,它的位置必须在这里,如果不行的话就说明这里不能成功拼接。

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    using namespace std;
    inline int read() {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    	while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    	return x * f;
    }
    const int N = 107;
    int n,sum,len,ans;
    int sticks[N];
    bool vis[N];
    bool cmp(int x,int y) {
    	return x > y;
    }
    bool Dfs(int tot,int now,int start) {	//保证每根木棍内元素递增 
    	if(tot*len == sum) return true;
    	if(now == len) return Dfs(tot+1,0,0);
    	for(int i=start;i<=n;++i) {
    		if(vis[i]) continue;
    		if(now+sticks[i] <= len) {
    			vis[i] = 1;
    			if(Dfs(tot,now+sticks[i],i+1)) return true;
    			vis[i] = 0;
    			if(!now) return false;	//这是第一个木棍,
    			if(now+sticks[i] == len) return false; //这是最后一根木棍
    			int j = i;
    			while(j<=n && sticks[j]==sticks[i]) ++j;
    			i = j - 1;	//跳过相同木棍 
    		}
    	}
    	return false;
    }
    void work() {
    	memset(vis, 0, sizeof(vis)); sum = 0; ans = -1;
    	for(int i=1;i<=n;++i) {
    		sticks[i] = read();
    		sum += sticks[i];
    	}
    	sort(sticks+1, sticks+1+n, cmp);
    	for(int i=1;i<=sum;++i) {
    		if(sum%i == 0) {
    			len = i;
    			if(Dfs(0,0,0)) {
    				ans = i; break;
    			}
    		}
    	}
    	printf("%d
    ",ans);
    }
    int main()
    {
    	while(true) {
    		n = read();
    		if(n == 0) break;
    		work();
    	}
    	return 0;
    }
    

    Summary

    • 看到搜索题第一步想优化枚举顺序

    • 第二步剪去等效状态

  • 相关阅读:
    ASM认证与口令文件
    asm 兼容性、asm 主要参数管理
    最常见的5个导致 RAC 实例崩溃的问题
    oracle隐含参数的查看与修改
    三种 Failover 之 Client-Side Connect time Failover、Client-Side TAF、Service-Side TAF
    Oracle RAC TAF 无缝failover
    oracle rac的特征
    安装ORACLE时在Linux上设置内核参数的含义
    关于GCC的理解——On the understanding of the GCC
    java中的闭包和回调
  • 原文地址:https://www.cnblogs.com/BaseAI/p/12148955.html
Copyright © 2020-2023  润新知