(hdu step 4.3.5)Sticks(将n根木棒合成若干根等长的木棒,求合成后的木棒的长度的最小值)

题目:

Sticks

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 364 Accepted Submission(s): 116
 
Problem Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero. 
 
Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
 
Output
The output file contains the smallest possible length of original sticks, one per line. 
 
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
 
Sample Output
6
5
 
 
Source
ACM暑期集训队练习赛(七)
 
Recommend
lcy


题目分析:

               DFS。



代码如下:

/*
 * e.cpp
 *
 *  Created on: 2015年2月25日
 *      Author: Administrator
 */


#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 65;

bool visited[maxn];//用于标记某个木棒是否已经使用过
int values[maxn];//结果序列
bool flag;//用于标记使用已经成功找到一种方案
int parts;//标记木棒的份数
int len;//等长木棒的长度
int n;//原始木棒序列的根数

/**
 * 深搜。
 * pos:当前搜索的的木棒的索引
 * cur:当前已经拼成的木棒的长度
 * cnt:当前已经拼好的木棒的数量
 */
void dfs(int pos,int cur,int cnt){


	if(cur == len){//如果当前木棒的长度==指定的木棒长度
		cnt++;//拼好的木棒的数量+1

		if(cnt == parts){//如果拼好的木棒数量==指定的木棒数量
			flag = true;//将flag标记为true,表示已经成功
			return ;//返回
		}
		//如果还没有拼够指定数量的等长木棒
		dfs(0,0,cnt);//则继续拼
	}


	if(pos >= n){//如果当前搜索到的木棒的索引已经超出了木棒的范围
		return ;//则返回,表示没有成功
	}


	int i;
	for(i = pos ; i < n ; ++i){//从当前木棒开始向后扫
		if(visited[i] == false  && values[i] + cur <= len){//如果该根木棒没有被访问过&&当前木棒的长度+已经拼好的木棒的长度<=len
			visited[i] = true;//则将该木棒标记为已经访问过
			dfs(i+1,values[i]+cur,cnt);//在此基础上继续往下搜
			visited[i] = false;//回滚

			/**
			 * 剪枝。
			 * 如果当前已经找到一种方案,则返回
			 * pos的那个剪枝我也还没有想明白,没加的时候TLE.
			 *
			 */
			if(flag == true|| pos == 0){
				return ;
			}


		}
	}
}


int main(){
	while(scanf("%d",&n)!=EOF,n){
		int maxLen = -1;
		int sum = 0;

		int i;
		for(i = 0 ; i < n ; ++i){
			scanf("%d",&values[i]);

			if(values[i] > maxLen){
				maxLen = values[i];//计算所有木棒中的最大长度
			}
			sum += values[i];//计算所有木棒的总长度
		}


		/**
		 * 从单根木棒的最大长度开始枚举所有情况。
		 * 为什么从但根木棒的最大值开始枚举而不是从最小值开始枚举呢?因为最小值的情况下,
		 * 比最小值长度要大的木棒必然会被废弃.这很明显不符合题意
		 */
		for(len = maxLen ; len < sum ; ++len){
			if(sum%len == 0){//如果该长度下,木棒能够被等分
				memset(visited,false,sizeof(visited));
				parts = sum/len;//计算该长度下能分成多少根木棒
				flag = false;//重新将flag设置成false
				dfs(0,0,0);//开始搜索

				if(flag == true){//如果已经成功
					break;//跳出循环
				}
			}
		}

		printf("%d\n",len);//输出找到的合成后的木棒的最小的长度
	}

	return 0;
}





  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,关于 HDU4992 所有原根的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原根。原根是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原根,那么 a 的任何正整数次幂对 n 取模的都不相同,且能覆盖所有与 n 互质的数。 2. 为了模 n 意义下的所有原根,我们需要先出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原根。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原根。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于最大公约数,phi 函数用于欧拉函数,pow 函数用于快速幂模,check 函数用于判断一个数是否是原根。在主函数中,我们依次读入每个 n,出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原根,将所有原根存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的东哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值