种树——拼多多笔试题(暴搜+剪枝)

题意

链接:https://www.nowcoder.com/questionTerminal/52f25c8a8d414f8f8fe46d4e62ef732c
来源:牛客网

小多想在美化一下自己的庄园。他的庄园毗邻一条小河,他希望在河边种一排树,共 M 棵。小多采购了 N 个品种的树,每个品种的数量是 Ai (树的总数量恰好为 M)。但是他希望任意两棵相邻的树不是同一品种的。小多请你帮忙设计一种满足要求的种树方案。
输入描述:
第一行包含一个正整数 N,表示树的品种数量。
第二行包含 N 个正整数,第 i (1 <= i <= N) 个数表示第 i 个品种的树的数量。
数据范围:
1 <= N <= 1000
1 <= M <= 2000
输出描述:
输出一行,包含 M 个正整数,分别表示第 i 棵树的品种编号 (品种编号从1到 N)。若存在多种可行方案,则输出字典序最小的方案。若不存在满足条件的方案,则输出"-"。

思路

直接搜索,看上去复杂度是阶乘级,但剪枝后就能过了,玄学。剪枝点是当出现一种树的数量大于剩余树的1/2时,就不满足条件了。

代码

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
	static final int N = 1005;
	static int[] a = new int[N];
	static int m=0,n,flag=0;
	static List<Integer> ans=new ArrayList<Integer>();
	static void dfs(int cnt) {
		for(int i=1;i<=n;i++) {
			if(a[i]>(m-cnt+1)/2)
				return ;
		}
		if(cnt==m) {
			flag=1;
			return ;
		}
		for(int i=1;i<=n;i++) {
			if(cnt==0||(a[i]>0&&ans.get(ans.size()-1)!=i)) {
				a[i]--;
				ans.add(i);
				dfs(cnt+1);
				if(flag==1)
					return ;
				ans.remove(ans.size()-1);
				a[i]++;
			}
		}
	}
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		for (int i = 1; i <= n; i++) {
			a[i] = in.nextInt();
			m += a[i];
		}
		dfs(0);
		if(flag==1) {
			for(int i:ans) {
				System.out.print(i+" ");
			}
			System.out.println();
		}else {
			System.out.println("-");
		}
	}
}

  

posted @ 2019-12-24 23:29  MCQ1999  阅读(626)  评论(0编辑  收藏  举报