给一堆数均匀分成N份--等边三角形/任务分配

题目一:等边三角形

手上有一些小木棍,它们长短不一,想用这些木棍拼出一个等边三角形,并且每根木棍都要用到。  例如,手上有长度为 1123333 的4根木棍,他可以让长度为112 的木棍组成一条边,另外 222跟分别组成 222条边,拼成一个边长为 3 的等边三角形。

首先输入一个整数 n(3≤n≤20)表示木棍数量,接下来输入 n 根木棍的长度 pi(1≤pi≤10000);

能拼出来输出Yes,否则输出no

import java.util.Arrays;
import java.util.Scanner;

public class 等边三角形 {
	static int flag = 0;
	static int leng[];
	static int singlength;
	static boolean flagcon;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner input = new Scanner(System.in);
		int n = input.nextInt();
		leng = new int[n];
		boolean visit[] = new boolean[n];
		int sum = 0;
		for (int i = 0; i < leng.length; i++) {
			leng[i] = input.nextInt(); 
			sum+=leng[i];
		}
		if (sum%3==0) {//3的倍数才有可能拼成三角形
			singlength = sum/3;
			for (int i = 0; i < leng.length; i++) {
				if (leng[i]>singlength) {
					System.out.println("no");//有一条边太大,也凑不成三角形
				}
			}
		}else {
			System.out.println("no");
			return;
		}
		Arrays.sort(leng);//长度排序
		dfs(visit, 0);
		if (flag==2) {//有两条边成功了,就拼成三角形
			System.out.println("yes");
		}else {
			System.out.println("no");
		}
	}
	/**
	 * @param visit 标记数组
	 * @param sticklength 已经拼凑的长度
	 */
	private static void dfs(boolean[] visit,int sticklength) {
		// TODO Auto-generated method stub
		if (flag==2) {
			return;
		}
		if (sticklength==singlength) {
			flagcon=true;//回溯的时候不要取消标记
			flag++;
			return;
		}
		if (sticklength>singlength) {
			return;
		}
		
		for (int i = 0; i < leng.length; i++) {
			if (visit[i]==false) {
				if (sticklength+leng[i]<=singlength) {
					visit[i]=true;
					sticklength+=leng[i];
					dfs(visit, sticklength);
					if (flagcon==false) {//回溯
						sticklength-=leng[i];
						visit[i]=false;
					}else {//flagcon=true,不取消标记
						flagcon=false;
						dfs(visit,0);//遍历第二个边
						return;
					}
				}else {
					break;//后面的棍子长度肯定大于singlength
				}
			}
		}
	}
}

题目二:

每个任务有一个所需的完成时间,现在需要将这些任务分配给一些人(每个人同时只能完成一个任务,每个任务都必须有人完成),使得每个人完成被分配的所有任务所需时间完全一样。你能算出最多能将这些任务分配给多少人么?

输入1:

27

10 7 9 10 13
23 2 3 31 1
5 6 7 8 9 6
6 5 4 1 2 3
3 11 13 12 6

输出1:6


输入:

9

5 2 1 5 2 1 5 2 1

输出4

import java.util.Arrays;
import java.util.Scanner;

public class 分配任务 {
	static int a[];
	static boolean flag;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner input = new Scanner(System.in);
		int n = input.nextInt();
//		int n=27;
		a = new int[n];
		int sum = 0;
		int maxsingtask = Integer.MIN_VALUE;
		for (int i = 0; i < a.length; i++) {
			a[i] = input.nextInt();
			if (maxsingtask<a[i]) {
				maxsingtask = a[i];//记录最大的单个任务量
			}
			sum += a[i];//记录总的任务量
		}
		Arrays.sort(a);//排序!!
		int maxpeoplenum = sum/maxsingtask+1;//能保证每个任务完成的情况下的最大人数;
		//遍历每一种分配方案
		for (int i = maxpeoplenum; i > 0; i--) {//分配给i个人
			if (sum%i==0) {//分配的尽的话
				int singtask = sum/i;//每个人得到singtask的任务量
				boolean visit[] = new boolean[n];
				dfs(i,singtask,singtask,visit);
				if (flag) {
					System.out.println(i);//这次分配个i个人行得通。并且肯定是最大人数。结束
					return;
				}
			}
		}
		System.out.println("end");
	}

	/**
	 * @param peoplenum 这次分配的人数
	 * @param inittasknum 分配的任务量-用来完成一个人初始化dfs的tasknum;
	 * @param tasknum 需要分配的任务量,tasknum=0则表示peoplenum个人的任务分配完毕
	 * @param visit 标记数组
	 */
	private static void dfs(int peoplenum, int inittasknum, int tasknum, boolean[] visit) {
		// TODO Auto-generated method stub
		if (peoplenum==0) {
			flag=true;
			return ;
		}
		
		for (int j = 0; j < a.length; j++) {
			if (visit[j]==false) {
				if (tasknum-a[j]>0) {//第peoplenum个人还没分配完
					visit[j]=true;
					tasknum -= a[j];
					dfs(peoplenum, inittasknum, tasknum, visit);//
					tasknum += a[j];//回溯
					visit[j]=false;
				}else if (tasknum-a[j]==0) {//分配完一个人的时候
					visit[j]=true;
					peoplenum--;
					dfs(peoplenum, inittasknum, inittasknum, visit);//这次分配的visit需要保留不用回溯
				}else {
					/*这里有疑问。用Arrays.sort(a); a排列后,这里应该使用break;但是程序会一直跑,为什么??9个任务的能跑出来,27个任务的一直在跑;
					 * 去掉Arrays.sort(a); 后27个任务的一下就出来了。不懂为什么排序后 会一直跑*/
					break;//减这个a[j]都不满足 ,减后面的更不满足;
//					continue;
				}
			}
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

obession

觉得有用可以打赏咖啡一杯~

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

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

打赏作者

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

抵扣说明:

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

余额充值