小木棍

传送门

这道题很明显是爆搜,但是爆搜肯定会T,我们来一步一步说。

首先木棍的原长不能小于所有木棍中最长的一段,否则那段就没用了。之后,木棍的原长也必须是总长的一个因子,而且必须是,小于等于他的一半的。这样已经减少一些不合法情况了,但是还远远不够。

之后我们考虑搜索时的操作,可以想到,我们应该先行使用长度较大的木棍,因为较小的木棍拼起来灵活一些,更适用于“补刀”,拼成功的概率更大一些。之后还有一个非常重要的操作,就是如果当前正在拼的这个木棍的剩余长度等于原长或者和现在这根木棍长度相等,但是接着搜下去却失败了,那我们直接回溯去改变原来的拼接方案。因为如果出现这种情况无法匹配的话,那么就说明这根木棍不能自己组成一根原来长度的木棍,那么它在后面也必然是没有用处的。那么我们没必要继续进行无用搜索,直接返回。

这样基本就可以过了。不过在UVA上的带有多组数据的……我的会T掉,不过mrclr大佬的代码就可以过了……看一下代码。

我的:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rg register
#define rep(i,a,n) for(rg int i = a;i <= n;i++)
#define per(i,n,a) for(rg int i = n;i >= a;i--)
#define enter putchar(‘\n‘)
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 70;
const int N = 10000005;
const int mod = 1000000009;

int read()
{
   int ans = 0,op = 1;
   char ch = getchar();
   while(ch < ‘0‘ || ch > ‘9‘)
   {
      if(ch == ‘-‘) op = -1;
      ch = getchar();
   }
   while(ch >=‘0‘ && ch <= ‘9‘)
   {
      ans *= 10;
      ans += ch - ‘0‘;
      ch = getchar();
   }
   return ans * op;
}

int n,a[M],cnt,maxn,x,tot;
bool vis[M];

bool cmp(int x,int y)
{
   return x > y;
}

//p stands for the current length,k stands for the sum of sticks
//goal stands for the goal length,cur stands for the number of the current stick
void dfs(int p,int k,int goal,int cur)
{
   if(k * goal == tot) printf("%d\n",goal),exit(0);
   if(p == goal)
   {
      dfs(0,k+1,goal,1);
      return;
   }
   if(goal - p < a[cnt]) return;
   rep(i,cur,cnt)
   {
      if(!vis[i] && p + a[i] <= goal)
      {
     vis[i] = 1;
     dfs(p+a[i],k,goal,i+1);
     vis[i] = 0;
     if(p + a[i] == goal || p == 0) break;
     while(a[i] == a[i+1]) i++;
      }
   }
}

int main()
{
   n = read();
   rep(i,1,n)
   {
      x = read();
      if(x <= 50) a[++cnt] = x,tot += a[cnt],maxn = max(maxn,a[cnt]);
   }
   sort(a+1,a+1+cnt,cmp);
   rep(i,maxn,tot >> 1) if(tot % i == 0) dfs(0,0,i,1);
   printf("%d\n",tot);
   return 0;
}

mrclr大佬的:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(‘ ‘)
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 70;
inline ll read()
{
  ll ans = 0;
  char ch = getchar(), last = ‘ ‘;
  while(!isdigit(ch)) {last = ch; ch = getchar();}
  while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - ‘0‘; ch = getchar();}
  if(last == ‘-‘) ans = -ans;
  return ans;
}
inline void write(ll x)
{
  if(x < 0) x = -x, putchar(‘-‘);
  if(x >= 10) write(x / 10);
  putchar(x % 10 + ‘0‘);
}

int n;
int num[maxn], Min = INF, Max = 0, sum = 0;
int ans = INF;

bool dfs(int res, int tot, int now, int p)
{
  if(!res) {ans = min(ans, now); return 1;}
  if(tot == now) return dfs(res - 1, 0, now, Max);
  else
    {
      for(int i = p; i >= Min; --i)
    {
      if(num[i] && i + tot <= now)
        {
          num[i]--;
          if(dfs(res, tot + i, now, i)) return 1;
          num[i]++;
          if(!tot || tot + i == now) return 0;
        }
    }
      return 0;
    }
}

void init()
{
  Mem(num, 0); Min = ans = INF; Max = sum = 0;
}

int main()
{
  while(scanf("%d", &n) && n)
    {
      init();
      for(int i = 1; i <= n; ++i)
    {
      int x = read();
      if(x > 50) continue;
      num[x]++;
      Min = min(Min, x);
      Max = max(Max, x);
      sum += x;
    }
      bool flg = 0;
      for(int i = Max; i <= (sum >> 1) && !flg; ++i)
    if(sum % i == 0)
      {
        if(dfs(sum / i, 0, i, Max)) flg = 1;
      }
      ans = min(ans, sum);
      write(ans), enter;
    }
  return 0;
}

原文地址:https://www.cnblogs.com/captain1/p/9873972.html

时间: 2024-10-17 20:37:17

小木棍的相关文章

P1120 小木棍 [数据加强版]

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

洛谷P1120小木棍[DFS]

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

小木棍 [数据加强版]

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

【搜索】小木棍

[搜索]小木棍 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度. 输入 共有二行. 第一行为一个单独的整数N表示看过以后的小木柜的总数,其中N≤60,第二行为N个用空个隔开的正整数,表示N跟小木棍的长度. 输出 仅一行,表示要求的原始木棍的最小可能长度. 样例输入 9 5 2 1 5 2 1 5 2 1 样例输出

洛谷 P1120 小木棍

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

小木棍 (codevs 3498)题解

[问题描述] 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过100. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度. [样例输入] 9 5 2 1 5 2 1 5 2 1 [样例输出] 6 [解题思路] 这道题的核心思想就一个字,搜……首先找到最大的那一段,原始木棍的可能长度必定>=最大的那一段木棍的长度,所以我们从最大的那一段长度开始往木棍总长度搜,将木棍排序,定义f布尔

洛谷P1120 小木棍

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

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

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

小木棍(爆搜减枝)

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

[UVA307]小木棍 Sticks

题目大意:有一堆小木棍,把它们接成相同长度的小木棍,问结果的小木棍的最小长度是多少,多组数据 题解:$dfs$,各种剪枝. 卡点:无 C++ Code: #include <cstdio> #include <algorithm> #include <cstdlib> #define maxn 55 const int inf = 0x3f3f3f3f; int n, Min, Max, sum; int cnt[maxn]; bool halt; void dfs(i