小多想在美化一下自己的庄园。他的庄园毗邻一条小河,他希望在河边种一排树,共 M 棵。小多采购了 N 个品种的树,每个品种的数量是 Ai (树的总数量恰好为 M)。但是他希望任意两棵相邻的树不是同一品种的。小多请你帮忙设计一种满足要求的种树方案。
小多想在美化一下自己的庄园。他的庄园毗邻一条小河,他希望在河边种一排树,共 M 棵。小多采购了 N 个品种的树,每个品种的数量是 Ai (树的总数量恰好为 M)。但是他希望任意两棵相邻的树不是同一品种的。小多请你帮忙设计一种满足要求的种树方案。
第一行包含一个正整数 N,表示树的品种数量。
第二行包含 N 个正整数,第 i (1 <= i <= N) 个数表示第 i 个品种的树的数量。
数据范围:
1 <= N <= 1000
1 <= M <= 2000
输出一行,包含 M 个正整数,分别表示第 i 棵树的品种编号 (品种编号从1到 N)。若存在多种可行方案,则输出字典序最小的方案。若不存在满足条件的方案,则输出"-"。
3 4 2 1
1 2 1 2 1 3 1
修改了很久
我觉得以上答案不够完美,有些很繁琐
#include <bits/stdc++.h> using namespace std; bool dfs(vector<int>& nums, vector<int>& results, int m, int prev) { if (m == 0) { return true; } for (int i = 0; i < nums.size(); ++i) { if ( nums[i] * 2 > m + 1) { return false; } if (nums[i] && prev != i) { nums[i]--; results.push_back(i); if ( dfs(nums, results, m - 1, i) ) { return true; } results.pop_back(); nums[i]++; } } return false; } int main() { int n, m ; cin >> n; vector<int> nums(n), results; m = 0; for (int i = 0; i < n; ++i) { cin >> nums[i]; m += nums[i]; } if (dfs(nums, results, m, -1) ) { for (auto c : results) { cout << c + 1 <<" "; // 下标为 1 - n 而存储的是 0 - n - 1 即数组下标 } cout << endl; } else { cout<<"-"<<endl; } return 0; }
/* DFS,需要判断不成立的情况下剪枝 */ #include <bits/stdc++.h> using namespace std; int idx_max(int a[], int n) {// 找出a中最大值的下标 int idx = -1, t_max = 0; for(int i = 0; i < n; i++) { if(a[i] > t_max) { idx = i; t_max = a[i]; } } return idx; } bool dfs(int a[], int b[], int n, int &m, int step) { int idx = idx_max(a, n); if(idx == -1) return true; if(a[idx] * 2 > m + 1) return false; //剪枝 if(a[idx] * 2 == m + 1) { //有上一句剪枝,可不用此步 a[idx]--; m--; b[step] = idx + 1; //此情况只有一种正确选择 if(dfs(a, b, n, m, step + 1)) return true; a[idx]++; m++; } else { for(int i = 0; i < n; i++) { if(a[i] > 0 && (step == 0 || b[step - 1] != i + 1)) { a[i]--; m--; b[step] = i + 1; if(dfs(a, b, n, m, step + 1)) return true; a[i]++; m++; } } } return false; } int main(void) { //freopen("input.txt", "r", stdin); int n, m = 0; scanf("%d", &n); int a[n]; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); m += a[i]; } int b[m], t_sum = m; if(dfs(a, b, n, t_sum, 0)) { for (int i = 0; i < m; i++) { printf("%d ", b[i]); } } else printf("-"); return 0; }
#include <stdio.h> int a[1003]; int ret[2003]; int n; int dfs(int step, int have) { if (have == 0) return 1; int i; for (i = 1; i <= n; i++) { if (a[i] > (have - a[i] + 1)) return 0; if (a[i] <= 0) continue; if (step == 0 || ret[step - 1] != i) { ret[step] = i; a[i]--; if(dfs(step + 1, have - 1)) return 1; a[i]++; } } } int main() { int sum = 0; int i; scanf("%d", &n); for (i = 1; i <= n; i++) { scanf("%d", a + i); sum += a[i]; } if (dfs(0, sum)) { for (i = 0; i < sum; i++) { printf("%d ", ret[i]); } printf("\n"); } else { printf("-\n"); } return 0; }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.ArrayList; public class Main { static ArrayList<Integer> scheme = new ArrayList<>(); // 方案数组,第i个元素表示第i个位置放置的树的品种编号 public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); int m = 0; String[] strArr = br.readLine().trim().split(" "); int[] treeType = new int[n]; for(int i = 0; i < n; i++) { treeType[i] = Integer.parseInt(strArr[i]); m += treeType[i]; } if(dfs(treeType, m, -1)){ // 存在可行方案 for(int i = 0; i < scheme.size(); i++) System.out.print((scheme.get(i) + 1) + " "); }else System.out.println("-"); } private static boolean dfs(int[] treeType, int m, int prev) { if(m == 0) return true; // 树用完了,返回true for(int i = 0; i < treeType.length; i++){ if(treeType[i]*2 > m + 1) // 剪枝,某一种类型的树大于总数的一半肯定无法达成相邻树的品种不同 return false; if(treeType[i] > 0 && prev != i) { // 如果i品种的树还有,且前一棵树不是i品种,就在本位置种植品种i的树 treeType[i]--; scheme.add(i); if(dfs(treeType, m - 1, i)) return true; // 回溯 scheme.remove(scheme.size() - 1); treeType[i]++; } } return false; } }
/*DFS+剪枝 */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; vector<int>ans; bool flag; /* n:树的种类 m:还有多少树没有种 last:上一棵树种的是哪一个*/ void Dfs(int *a, int n, int m, vector<int>ans, int last){ if(m==0){ for(int i=0; i<ans.size(); i++){ printf("%d%c", ans[i], i==(ans.size()-1)?'\n':' '); } flag=true; return; } for(int i=1; i<=n; i++){//剪枝 if(a[i]>(m+1)/2) return; } for(int i=1; i<=n; i++){ if(a[i]>0 && i!=last){ a[i]--, ans.push_back(i); if(!flag) Dfs(a, n, m-1, ans, i); a[i]++, ans.pop_back(); } } } int main(){ int n, m; int a[1005]; while(~scanf("%d", &n)){ m=0; for(int i=1; i<=n; i++) scanf("%d", &a[i]), m+=a[i]; ans.clear(); flag=false;//全局变量标记是否找到最优解 Dfs(a, n, m, ans, -1); if(!flag) printf("-\n"); } return 0; }
/* 贪心递归 首先判断是否可行:只要最多的一种树的数量*2<所有树的总量+1,就肯定有可行解 对于可行解,我们每一次种树的时,只需要考虑: 1.从编号小到大遍历,找到第1个数量不为0且和前一颗树编号不同的编号 2.1 若这种树是目前最多的树,中了它 2.2 若这种树不是目前最多的,但中了它之后剩下的树仍可行,中了它 2.3 若这种树不是目前最多的,中了它后就不可行了,那别说啥了,找到目前最多的那种,中了它 (写完感觉这个判断条件逻辑的内外层应该反过来= =有空再改吧) */ #include<iostream> #include<vector> using namespace std; vector<int> fun(vector<int> &v, int maxv, int sumv, int pre) { vector<int> res; int i = 0; while(v[i] == 0 || i == pre) { i++; } if(sumv == 1) { res.push_back(i+1); return res; } else { if(v[i] == maxv) { v[i]--; maxv = maxv - 1; for(int j = i+1; j < v.size(); j++) { maxv = max(maxv, v[j]); } res = fun(v, maxv, sumv-1, i); res.insert(res.begin(),i+1); return res; } else { if(maxv*2 < sumv + 1){ v[i]--; res = fun(v, maxv, sumv-1, i); res.insert(res.begin(),i+1); return res; } else{ while(v[i] != maxv || i == pre) { i++; } v[i]--; maxv = maxv - 1; for(int j = i+1; j < v.size(); j++) { maxv = max(maxv, v[j]); } res = fun(v, maxv, sumv-1, i); res.insert(res.begin(),i+1); return res; } } } } int main() { int N; cin>>N; int tmp; vector<int> v; vector<int> res; int maxv = 0, sumv = 0; for(int i = 0; i < N; i++) { cin>>tmp; v.push_back(tmp); maxv = maxv > tmp ? maxv:tmp; sumv = sumv + tmp; } if(maxv*2 > sumv + 1) { cout<<"-"<<endl; return 0; } res = fun(v, maxv, sumv, -1); for(int i = 0; i < res.size() - 1; i++) { cout<<res[i]<<" "; } cout<<res[res.size()-1]; return 0; }
全用深搜,数据一大就凉。
其实贪心就可以搞定(当然debug了比较久,在那个判断一定要种的条件上)
先判断是否一定要种剩余数量最多的树(判断条件是【最大树数量为奇数&&(剩余树数量+1)/2==最大树数量】);一定要种的话,再判断是否上一棵树序号相同,相同就选数量第二多的数(其实这样下一步就已经能确定无法满足条件了)。
不是一定的话就选序号最小的树种,上一次种过么就选第二小的。
有问题的话欢迎指出
#include<iostream> (720)#include<vector> #include<string> using namespace std; int N; int number[4000]; int res[4000]; int main(){ cin >> N; int M = 0; for(int i = 0 ; i < N; i++){ int tmp ; cin >> tmp; M += tmp; number[i] = tmp; } for(int i = 0 ; i < M; i++){ int max_tree = -1; int max_number = 0; int max2_tree = -1; int max2_number = 0; for(int j = 0 ; j < N; j++){ if(number[j] > max_number){ // 存第二大的,之前最大总是大于第二大 max2_number = max_number; max2_tree = max_tree; max_number = number[j]; max_tree = j; } else{ if(number[j] > max2_number){ // 存第二大的 max2_number = number[j] ; max2_tree = j; } } } int remain = M- i; if((remain+1)/2 < max_number){ cout<< "-" << endl; return 0; } // 只能种这个树 int test = 0; if(remain%2 == 1 && (remain+1)/2 == max_number){ // 相邻不是一种树 if(i == 0 || (i > 0 && res[i-1] != max_tree)){ res[i] = max_tree; number[max_tree]--; } else{ res[i] = max2_tree; number[max2_tree]--; } } else{ int j, j2; for(j = 0 ; j < N && !number[j]; j++){} for(j2 = j+1 ; j2 < N && !number[j2]; j2++){} if(i == 0 || (i > 0 && res[i-1] != j)){ res[i] = j; number[j]--; } else{ res[i] = j2; number[j2]--; } } } for(int i = 0 ; i < M; i++){ cout << res[i]+1; if(i != M-1) cout << " "; else cout << endl; } return 0; }
import sys # python 默认递归深度不超过1000,做dfs会比C吃亏 sys.setrecursionlimit(10000000)# 手动修改深度,如果TLE那就是算法的问题 # 小多采购了 N 个品种的树,每个品种的数量是 Ai (树的总数量恰好为 M) N = int(input()) arr = list(map(int, input().split())) # sum(arr) = M M = sum(arr) res = [] def dfs(a, m, pre_tree_class): if m == 0: return True for i in range(len(a)): tree_class = i+1 if a[i]*2 > m+1: return False if a[i]>0 and pre_tree_class != tree_class: a[i] -= 1 res.append(tree_class) if dfs(a, m-1, tree_class): return True res.pop(-1) a[i] += 1 return False try: if dfs(arr, M, 0): print(" ".join(map(str, res))) else: print("-") except Exception as e: print(e)
package 种树; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /* * 小多想再美化一下自己的庄园。他的庄园毗邻一条小河,他希望在河边种一排树,共 M 棵。 * 小多采购了 N 个品种的树,每个品种的数量是 Ai (树的总数量恰好为 M)。 * 但是他希望任意两棵相邻的树不是同一品种的。 * 小多请你帮忙设计一种满足要求的种树方案。 * * 输入描述: * 第一行包含一个正整数 N,表示树的品种数量。 * 第二行包含 N 个正整数,第 i (1 <= i <= N) 个数表示第 i 个品种的树的数量。 * 数据范围:1 <= N <= 1000,1 <= M <= 2000 * * 输出描述: * 输出一行,包含 M 个正整数,分别表示第 i 棵树的品种编号 (品种编号从1到 N)。 * 若存在多种可行方案,则输出字典序最小的方案。 * 若不存在满足条件的方案,则输出"-"。 * * 示例1 * 输入 * 3 * 4 2 1 * * 输出 * 1 2 1 2 1 3 1 */ /* * 算法:DFS、剪枝优化 * 数据结构:ArrayList * 剪枝思路:每次搜索之前判断当前剩余的空间大小和任意品种的树之间的关系: * 1) 如果freeSpaceSize为偶数,那么只要treeQuantityArray[treeCategory] > freeSpaceSize / 2,就不能保证相邻树种不同 * 2) 如果freeSpaceSize为奇数,那么只要treeQuantityArray[treeCategory] > (freeSpaceSize + 1) / 2,就不能保证相邻树种不同 * tip:freeSpaceSize为偶数时,treeQuantityArray[treeCategory] > freeSpaceSize / 2 和treeQuantityArray[treeCategory] > (freeSpaceSize + 1) / 2的值是相等的。 * 所以可以统一使用treeQuantityArray[treeCategory] > (freeSpaceSize + 1) / 2的关系来做剪枝优化! */ public class Main { //剩余空间大小是否能保证,在相邻树种不同的情况下,能放下任意品种的树(够放最大数量的树种) private static boolean checkIfFreeSpaceEnough(int treeCategorySize, int[] treeQuantityArray, int freeSpace) { for (int treeCategory = 1; treeCategory <= treeCategorySize; treeCategory++) { if (treeQuantityArray[treeCategory] > (freeSpace + 1) / 2) { return false; } } return true; } //深度优先搜索,寻找是否存在按规则分布的序列 private static boolean DFS(int treeDistributionIndex, int[] treeQuantityArray, int treeCategorySize, List<String> treeDistributionList, int treeQuantitySum) { //形成按规则分布的序列,DFS成功标志 if (treeDistributionIndex == treeQuantitySum) { return true; } //剩余空间是否充足,剩余空间即剩下要放的树的数量 int freeSpace = treeQuantitySum - treeDistributionIndex; if (! checkIfFreeSpaceEnough(treeCategorySize, treeQuantityArray, freeSpace)) { return false; } for (int treeCategory = 1; treeCategory <= treeCategorySize; treeCategory ++) {//字典序实现 //treeQuantityArray[treeCategory] != 0表示某一树种不用尽 //treeCategory != Integer.valueOf(treeDistributionList.get(treeDistributionIndex - 1))表示相邻树种不该相同 if (treeDistributionIndex == 0 || treeQuantityArray[treeCategory] != 0 && treeCategory != Integer.valueOf(treeDistributionList.get(treeDistributionIndex - 1))) { treeQuantityArray[treeCategory] --; //int值+""->String treeDistributionList.add(treeCategory + ""); if (DFS(treeDistributionIndex + 1, treeQuantityArray, treeCategorySize, treeDistributionList, treeQuantitySum)) { return true; } //某一条分路走不下去返回false了(放树顺序错了,如放该种树后面数目更大的树种将放不下) //回退,跳过该树放数目更大的树种 treeQuantityArray[treeCategory] ++; treeDistributionList.remove(treeDistributionList.size() - 1);//将序列末尾值去除 } } //无法形成按规则分布的序列,dfs失败标志 return false; } public static void main(String[] args) { Scanner input = new Scanner(System.in); int treeCategorySize = input.nextInt(); int[] treeQuantityArray = new int[treeCategorySize + 1]; int treeQuantitySum = 0; //题目要求树种从1开始 for (int treeCategory = 1; treeCategory <= treeCategorySize; treeCategory ++) { treeQuantityArray[treeCategory] = input.nextInt(); treeQuantitySum += treeQuantityArray[treeCategory]; } input.close(); List<String> treeDistributionList = new ArrayList<String>(); //若存在按规则分布的序列 if (DFS(0, treeQuantityArray, treeCategorySize, treeDistributionList, treeQuantitySum)) { System.out.println(String.join(" ", treeDistributionList));//分布序列元素间加上空格 } //若不存在按规则分布的序列 else { System.out.println("-"); } } }
#include<iostream> #include<vector> using namespace std; //a为数组,a[i]表示第i个品种的数量,从0开始;b表示最后结果;m为总的数量;prev为前一棵树; //dfs搜索,没啥问题直接过 bool dfs( vector<int>& a, vector<int>& b, int &m, unsigned prev){ if(m==0) return true; for(int i=0;i<a.size();i++){ if(2*a[i]>m+1) return false; if(a[i]>0&&prev!=i){//a[i]颗树还可以种 b.push_back(i+1);//种一颗树树 a[i]--; m--; if(dfs(a,b,m,i)) return true;//输出最小字典序 else{ b.pop_back(); a[i]++; m++; } } } } int main() { int n, m = 0; cin>>n; vector<int> a(n);//第i个品种的树的类目为a[i],树的总类目为n for (int i = 0; i < n; i++) { cin>>a[i]; m+=a[i]; } vector<int> b;//保存的种树方案 int m1= m; if(dfs(a, b, m1, -1)) { for (int i = 0; i < m; i++) { cout<<b[i]<<" "; } cout<<endl; } else cout<<"-"<<endl; return 0; }参考了别的代码,稍微修改了一下,基本思路是dfs
思路:
使用搜索来做,但纯粹使用搜索的话通过率为90%,有一个点会超时,所以需要剪枝,一个简单的剪枝思路是比较当前未种的树和坑的大小关系!
具体的剪枝思路是每次搜索之前判断当前剩余的坑位left和任意品种的树之间的关系:
1) 如果left为偶数,那么只要tree[i] > left / 2,就表示肯定种不了
2) 如果left为奇数,那么只要tree[i] > (left + 1) / 2,就表示肯定种不了
这里有一个小技巧:left为偶数时,left/2 和(left + 1)/2的值是相等的,所以可以统一使用tree[i] > (left+1)/2的关系来做剪枝优化!
import java.util.*; public class Main { static int n, m; static int[] tree; static List<String> ans; static boolean check(int left) { for (int i = 1; i <= n; i++) { if (tree[i] > (left + 1) / 2) return false; } return true; } static boolean dfs(int idx) { if (!check(m - idx)) return false; if (idx == m) { return true; } else { for (int i = 1; i <= n; i++) { if (idx == 0 || (tree[i] != 0 && i != Integer.valueOf(ans.get(idx - 1)))) { tree[i]--; ans.add(i + ""); if (dfs(idx + 1)) return true; ans.remove(ans.size() - 1); tree[i]++; } } } return false; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { n = sc.nextInt(); tree = new int[n + 1]; for (int i = 1; i <= n; i++) { tree[i] = sc.nextInt(); m += tree[i]; } ans = new ArrayList<>(); if (dfs(0)) { System.out.println(String.join(" ", ans)); } else { System.out.println("-"); } } } }
importjava.util.Scanner;
//1、首先判断能不能种树。如果是奇数,如果某种树大于(M+1)的一半则不能种,
如果是偶数,则大于M的一半不能种树
// 2、每次种树前都要判断是不是某种树大于一半,如果是,本次种该树。
如果不是再从下网上遍历数组,优先种序号小的树(要保证该序号的树还有的剩,且不等于之前种的树)
publicc***in {
publicstaticvoidmain(String[] args) {
Scanner input =newScanner(System.in);
intN=input.nextInt();
int[] nums=newint[N];
intM=0;
for(inti = 0; i <N ; i++) {
nums[i]=input.nextInt();
M+=nums[i];
}
if(M%2==0){//如果是偶数
for(inti = 0; i <N ; i++) {
if(nums[i]>M/2){
System.out.println("-");
return;
}
}
}else{//如果是奇数
for(inti = 0; i <N ; i++) {
if(nums[i]>(M+1)/2){
System.out.println("-");
return;
}
}
}
StringBuffer res=newStringBuffer();
intcount=M;
intpre=-1;
for(inti=0;i<M;i++){
booleanflag=false;
for(intk=0;k<N;k++){
if(nums[k]>count/2){//判断是否有树大于剩余的一半
res.append(k+1);
res.append(" ");
nums[k]--;
pre=k+1;
flag=true;
count--;
break;
}
}
if(flag==true) continue;
intj=0;
while(nums[j]==0||(j+1)==pre){
j++;
}
nums[j]--;
pre=j+1;
res.append(j+1);
res.append(" ");
count--;
}
System.out.println(res.toString().trim());
}
}
#include <bits/stdc++.h> using namespace std; bool DFS(vector<int> &a, vector<int> &b, int &t, int x){ if(t==0) return true; for(int i=1;i<=a.size();i++){ if(a[i]*2>t+1) return false; if(a[i]>0 && i!=x){ a[i]--; t--; b.push_back(i); if(DFS(a, b, t, i)) return true; b.pop_back(); t++; a[i]++; } } return false; } int main(){ int n, s=0; cin>>n; vector<int> a(n+1); vector<int> b; for(int i=1;i<=n;i++){ cin>>a[i]; s += a[i]; } int t = s; if(DFS(a, b, t, 0)){ for(int i=0;i<s;i++){ if(i==s-1) cout<<b[i]<<endl; else cout<<b[i]<<" "; } }else{ cout<<"-"<<endl; } return 0; }
#include<iostream> #include<algorithm> using namespace std; const int N = 1005; const int M = 2005; bool flag = false; int n, a[N], sum, ans[M]; void dfs(int cnt, int x){ if(flag) return; if(cnt > sum){ flag = true; for(int i = 1; i <= sum; ++i) cout << ans[i] << " "; cout << endl; return; } int res = sum - cnt + 1; for(int i = 1; i <= n; ++i){ if(a[i] > (res + 1) / 2){ return; } } for(int i = 1; i <= n; ++i){ if(i == x) continue; if(a[i] > 0){ a[i]--; ans[cnt] = i; dfs(cnt + 1, i); ans[cnt] = 0; a[i]++; } } } signed main(){ cin >> n; for(int i = 1; i <= n; ++i){ cin >> a[i]; sum += a[i]; } dfs(1, 0); if(!flag) cout << "-" << endl; }
#include <iostream> #include <algorithm> #include <vector> #include <climits> using namespace std; bool ok = false; int n, m; vector<int> v, temp, ans; void dfs(int num, int pre) { if (ok) return ; if (num == m) { ok = true; ans = temp; return ; } for (int i = 0; i < v.size(); ++i) { if (v[i] * 2 > (m-num)+1) { return; } if (pre != (i+1) && v[i] > 0) { v[i]--; temp.push_back(i+1); dfs(num+1, i+1); if (ok) return; temp.pop_back(); v[i]++; } } } int main() { cin >> n; int x; for (int i = 0; i < n; ++i) { scanf("%d", &x); m += x; v.push_back(x); } dfs(0, 0); if (ok == false) cout << "-" << endl; for (int x : ans) { cout << x << " "; } return 0; }
代码复杂了一点,但是空间复杂度和时间复杂度都是O(n)。 举个例子: 输入3 2 4 1 第一轮:1212 第二轮:2还有剩余,插入后面的,121232 第三轮:2还是有剩余,开始在数组中找可插入的点,最后成为212132 struct listNode { int val; listNode* next; listNode(int _val) : val(_val), next(NULL) {}; }; int main() { int n; while (cin >> n) { vector<int> vec(n + 1, 0); for (int i = 1; i < n + 1; ++i) { int temp; cin >> temp; vec[i] = temp; } int total = accumulate(vec.begin(), vec.end(), 0), flag = 0, max; total % 2 == 0 ? max = total / 2 : max = total / 2 + 1; for (auto x : vec) { if (x > max) { cout << '-' << endl; flag = 1; } } if (flag) continue; int t = 0; while (vec[t] == 0) { t += 1; } listNode* head = new listNode(t), * tail = head; vec[t] -= 1; for (int i = 1; i < vec.size(); ++i) { int pos = i + 1; while (vec[i] != 0 and pos < vec.size()) { if (tail->val != i) { while (pos < vec.size() and vec[i] > 0) { if (vec[pos] == 0) continue; while (vec[pos] > 0 and vec[i] > 0) { listNode* temp1 = new listNode(pos); listNode* temp2 = new listNode(i); tail->next = temp2; temp2->next = temp1; tail = temp1; vec[pos] -= 1; vec[i] -= 1; } pos += 1; } } else { while (pos < vec.size() and vec[i] > 0) { if (vec[pos] == 0) continue; while (vec[pos] > 0 and vec[i] > 0) { listNode* temp1 = new listNode(pos); listNode* temp2 = new listNode(i); tail->next = temp1; temp1->next = temp2; tail = temp2; vec[pos] -= 1; vec[i] -= 1; } pos += 1; } } } if (vec[i] > 0) { vector<listNode*> ins; listNode* t_head = head; while (t_head != NULL) { if (t_head->val != i and (t_head->next == NULL&nbs***bsp;t_head->next->val != i)) { ins.push_back(t_head); } t_head = t_head->next; } if (ins.size() < vec[i]) { listNode* t1 = new listNode(i); t1->next = head; for (int j = 0; j < ins.size(); ++j) { listNode* t2 = ins[j]->next; listNode* t3 = new listNode(i); ins[j]->next = t3; t3->next = t2; } head = t1; } else { for (int j = 0; j < ins.size(); ++j) { if (ins.size() - j - 1 > vec[i] and ins[j]->val < i) continue; else { listNode* t5 = ins[j]->next; listNode* t6 = new listNode(i); ins[j]->next = t6; t6->next = t5; } } } } } while (head != NULL) { cout << head->val << " "; head = head->next; } cout << endl; } return 0; }
#include <iostream> #include <vector> #include <utility> using namespace std; pair<bool,vector<int>> solution( const vector<int> &trees, int current, int ntrees ) { if (ntrees == 0) return make_pair(true, vector<int>()); for (int i = 0; i < trees.size(); ++i) { // 剪枝,任意树的数量大于总数目的一般,肯定不能交替种树 if( trees[i] > (ntrees+1) /2 ) return make_pair(false, vector<int>()); if (i != current && trees[i] > 0 ) { vector<int> remain(trees); --remain[i]; pair<int,vector<int>> tmp = solution(remain, i, ntrees-1); if (tmp.first) { tmp.second.push_back(i+1); return tmp; } } } return make_pair(false, vector<int>() ) ; } int main() { int N; while (cin >> N) break; int tmp; int ntrees = 0; vector<int> trees(N,0); for (int i = 0; i < N; ++i) { cin >> trees[i]; ntrees += trees[i]; } pair<bool,vector<int>> ret = solution(trees, -1, ntrees ); if (ret.first) { for (auto iter = ret.second.rbegin(); iter != ret.second.rend(); ++iter) cout << *iter << " "; cout << endl; } else cout << "-" << endl; return 0; }
import java.util.*; /** * 深度遍历,优先选择种类小的树 **/ public class Main { private static boolean dfs(int[] curr, int index, int[] arr, int last) { int rest = curr.length - index; if (rest == 0) { for (int i : curr) System.out.print(i + 1 + " "); return true; } for (int tree : arr) { if (tree > (rest + 1) / 2) return false; } for (int i = 0; i < arr.length; i++) { if (arr[i] != 0 && i != last) { int[] temp = new int[arr.length]; System.arraycopy(arr, 0, temp, 0, arr.length); temp[i]--; int[] currTemp = new int[curr.length]; System.arraycopy(curr, 0, currTemp, 0, curr.length); currTemp[index] = i; if (dfs(currTemp, index + 1, temp, i)) return true; } } return false; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int count = scanner.nextInt(); int[] arr = new int[count]; int total = 0; for (int i = 0; i < count; i++) { int temp = scanner.nextInt(); arr[i] = temp; total += temp; } scanner.close(); int[] curr = new int[total]; if (!dfs(curr, 0, arr, -1)) { System.out.println("-"); } } }