洛谷P1120 小木棍

洛谷1120 小木棍

题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。
    现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。
    给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入输出格式

输入格式:

输入文件共有二行。
第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60
(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)
第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

输出格式:

输出文件仅一行,表示要求的原始木棍的最小可能长度

输入输出样例

输入样例#1:

9

5 2 1 5 2 1 5 2 1

输出样例#1:

6

【思路】

枚举+回溯法构造判定。

不难想到从小到大枚举原木棍的长度,但是长度最大可以为300,太大了,我们换而从小到大枚举原木棍根数num,只要可以构造出num根相同长度len的木棍则完成任务。

如何判定能够构造成功?回溯法。

先对数据由大到小sort,这样在搜索的时候会先尝试长度大的木棍,显然先选大长度的木棍是优于选小长度的,因为小长度会更有用(可以组合的更多)。

以目前组装的第几根木棍d、目前组装的长度nowlen以及该从哪开始枚举木棍的下标nowi为状态,搜索是否能够使d==num+1即可。

剪枝:

1、   木棍数目枚举范围:最大为 长度和/最大长度

2、   木棍数目是否符合要求:木棍数目为总长度的约数。

3、   后缀和判断解不可行。

4、   Nowi的使用减少同一根小棒的枚举

5、   每次组装新的木棍的时候人为选择最长的木棍(加速枚举中nowlen+a[i]<len的判断,否则会多拓展一层)

【代码】

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4
 5 const int maxn = 60+10;
 6
 7 int a[maxn],cnt[maxn];
 8 int len,num,n;
 9 int suff_s[maxn];
10
11 inline bool cmp(const int& a,const int& b) {
12     return a>b;
13 }
14 bool dfs(int d,int nowlen,int nowi) {
15     if(d==num) return true;
16
17     if(len-nowlen > suff_s[nowi]) return false;
18
19     for(int i=nowi;i<n;i++) if(cnt[a[i]]) {
20        if(a[i]+nowlen < len) {
21                 cnt[a[i]]--;
22                 if(dfs(d,nowlen+a[i],i+1)) return true;
23                 cnt[a[i]]++;
24        }
25        if(a[i]+nowlen==len) {
26                   cnt[a[i]]--;
27                   int j;
28                for(j=0;j<n;j++) if(cnt[a[j]]&&a[j]<len) break;
29                cnt[a[j]]--;
30                if(dfs(d+1,a[j],j+1)) return true;
31                cnt[a[j]]++;
32                cnt[a[i]]++;
33         }
34     }
35     return false;
36 }
37 int main() {
38     ios::sync_with_stdio(false);
39     cin>>n;
40     int tot=0,x,_max=0,maxx=0;
41     for(int i=0;i<n;i++) {
42         cin>>x;
43         if(x<=50) {
44            a[tot++]=x;
45            suff_s[tot-1]=x;
46            _max+=x;
47            maxx=max(maxx,a[tot-1]);
48            cnt[x]++;
49         }
50     }
51     n=tot;
52     for(int i=n-2;i>=0;i--) suff_s[i] += suff_s[i+1];
53     sort(a,a+n,cmp);
54     int t=_max/maxx; if(t>n) t=n;
55     cnt[a[0]]--;
56     for(num=t;num>=0;num--) if(_max%num==0) {
57         len=_max/num;
58         if(dfs(0,a[0],1)) {
59             cout<<len;
60             break;
61         }
62     }
63     return 0;
64 } 
时间: 2024-12-15 06:58:59

洛谷P1120 小木棍的相关文章

洛谷P1120小木棍[DFS]

题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度. 输入输出格式 输入格式: 输入文件共有二行. 第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60 (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!) 第二行为N个用空个隔开的正整数,表示N根小木棍的长度. 输出格式: 输出文件仅一行,表示要求

洛谷 P1120 小木棍

题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度. 输入输出格式 输入格式: 输入文件共有二行. 第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60 (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!) 第二行为N个用空个隔开的正整数,表示N根小木棍的长度. 输出格式: 输出文件仅一行,表示要求

luogu P1120 小木棍 [数据加强版]

二次联通门 : luogu P1120 小木棍 [数据加强版] /* luogu P1120 小木棍 [数据加强版] 暴搜 + 剪枝 枚举可能的长度 挨个检查答案 二分显然正确性不能保障 搜索时从最大的开始找 放上当前木棍后的长度比枚举的长度要大, 则退出 若当前的长度与当前扫到的木棍长度相同, 或是还需要的长度与枚举的长度相同,则退出 若当前的木棍不符合要求, 则后面与它长度相同的木棍都不行 */ #include <algorithm> #include <iostream>

【基础练习】【背包DP】洛谷1164 小A点菜题解

洛谷的题目又有那令人···的悲剧格式= = 洛谷1164 小A点菜 本题地址:http://www.luogu.org/problem/show?pid=1164 题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家--餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:"随便点". 题目描述 不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩M元(M<=10000). 餐馆虽低端,但是菜品种类不少,有N种(N<=100),第i种

洛谷 3951 小凯的疑惑

洛谷 3951 小凯的疑惑 题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小 凯想知道在无法准确支付的物品中,最贵的价值是多少金币?注意:输入数据保证存在 小凯无法准确支付的商品. 输入输出格式 输入格式: 输入数据仅一行,包含两个正整数 aa 和 bb ,它们之间用一个空格隔开,表示小凯手 中金币的面值. 输出格式: 输出文件仅一行,一个正整数 NN ,表示不找零的情况下,小凯用手中

洛谷 P3951 小凯的疑惑

问题描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小凯想知道在无法准确支付的物品中,最贵的价值是多少金币?注意:输入数据保证存在小凯无法准确支付的商品. 输入格式 输入文件名为math.in. 输入数据仅一行,包含两个正整数 a 和 b,它们之间用一个空格隔开,表示小凯手中金币的面值. 输出格式 输出文件名为math.out. 输出文件仅一行,一个正整数 N,表示不找零的情况下,小凯用手中的

P1120小木棍

题目传送P1120 有许多剪枝的搜索 先考虑答案的范围,先把小木棍排个序,原木棍的长一定大于等于最长的一根 然后,就枚举一下原木棍的长度,搜是否能按这个长度拼成所有的木棍,如果能拼成直接就是答案了 确定了原始长度,然后用总长度就能算出原始木棍的条数.如果不能整除的话,肯定不是答案 然后确定搜索的状态,当前拼到第几跟,这一根还剩多长,拼这一根用的上一根小木棍的编号 我们肯定要先拼大的,再用小的去补大的 如果我们用小的凑的话,那些大的很难凑齐 还有一个优化就是,有很多长度相同的小木棍,对于一种长度不

P1120 小木棍 [数据加强版]

题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度. 输入输出格式 输入格式: 输入文件共有二行. 第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65 (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!) 第二行为N个用空个隔开的正整数,表示N根小木棍的长度. 输出格式: 输出文件仅一行,表示要求

P1120 小木棍 [数据加强版] 题解

原题链接 简要题意: 把若干 \(\leq 50\) 的小木棍拼成若干长度相同的长木棍(一个小木棍也可以作为一根长木棍).求可以拼成的长木棍的最小长度. 暴力出奇迹 一看数据范围,\(n \leq 65\). 这一看就是指数级复杂度 我还没见过什么 \(O(n^5)\) 的算法.. 首先考虑 \(\texttt{dfs}\),枚举长木棍的长度,然后用 \(\texttt{dfs}\) 进行暴力枚举当前的小木棍分给哪一组(可以算出组数的),验证即可. 对这种最 卑劣 不太行的搜索,下面开始大力剪枝