题解:
题目难度:三星
考察点: 深度优先搜索,回溯,剪枝
易错点:
这个题目对于同学们来说做法非常直接,就是递归+回溯,也很容易想。但是因为物品的数量达到了,如果用简单的不进行剪枝的话,是无法跑过所有数据的,因此需要做一些剪枝。
题解:深度优先搜索+剪枝
这个题目的做法很显然,就是使用递归+回溯,每次从编号枚举物品,如果当前物品的数量不为,且已经排好了的上一个和当前物品不同,则可以把当前物品加入序列,然后不断递归下去,直至所有的物品都被取完。然后这里存在一个可以剪枝的地方,如果当前序列中数量最多的物品都数量的倍,大于剩余物品数量加,则说明当前的摆放方式是不合法的,可以直接剪掉。因为这种情况下,不可能让两个相邻的物品都不是同一种。加上这个剪枝,也就能轻松这道题目了。
#include "bits/stdc++.h" using namespace std; const int maxn=2000+10; int n,a[maxn],b[maxn]; int check(){ int pos=-1,mx=0; for(int i=1;i<=n;i++){ if(a[i]>mx){ mx=a[i]; pos=i; } } return pos; } bool dfs(int cur,int m){ int pos=check(); if(pos==-1) return true; if(a[pos]*2>m+1) return false; for(int i=1;i<=n;i++){ if(a[i]&&b[cur-1]!=i){ a[i]--; m--; b[cur]=i; if(dfs(cur+1,m)) return true; a[i]++; m++; b[cur]=0; } } } int main() { scanf("%d",&n); int m=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); m+=a[i]; } if(dfs(1,m)){ for(int i=1;i<=m;i++) printf("%d ",b[i]); printf("\n"); }else{ printf("-\n"); } return 0; }