😊 | Powered By HeartFireY |
Problem Description
题目大意:给定一个括号序列,"(“表示火车进站,”)"表示火车出站。火车具有不同的颜色,颜色的类型由题目给定。每个时刻火车站内的火车颜色可以视为一个序列。现在要求你求一个火车进站的顺序,使得每个时刻的颜色序列都不相同。
实际上就是给定出入栈的序列,然后使每次入栈之后的序列各不相同。首先来看样例的入栈火车颜色图解
考虑如何构造这些不同的序列。我们可以发现:实际上所有序列构成一个森林,森林的每棵树上存储操作序列。为了使序列满足题意,我们需要使每个非叶子节点的子树的点颜色不同。
那么我们沿着这个思路继续,为了保证每个非叶子节点的子树颜色不同,我们需要在回溯的时候对子节点进行染色。这里引用yezzz.的一组样例并加颜色数据:
11
((())()((())))()(()())
4 4 4 2 1 3 5 5 6 6 4
按照以上括号序列,我们逐个节点建树,首先建到节点后碰到
开始回溯,
节点无子节点,因此染色操作直接
,然后继续,又碰到一个
,继续回溯到
,执行染色操作,将
的子节点染一次色。这里染色要特别说明一下,我们在这里根据贪心的思想,从数目最多的颜色开始染色,染到子树全部染色为止。
然后继续遍历,碰到,那么继续往下走
如此重复这个过程,直到整个森林全部被染色完毕。
那么代码怎么写?我们可以用一个栈暂存建树过程中每一层的节点,染色后出栈;对于染色的过程,将所有颜色出现的次数和颜色代号存入优先队列,染色时根据节点数将颜色依次出队,如果颜色不够那么说明不符合题目要求,输出“NO”,然后再用一个栈暂存出队的节点,减去染色的一次后再存回去。如下:第一棵树的染色步骤如下描述:
Accepted Code
#include <bits/stdc++.h>
#define pii pair<int, int>
using namespace std;
const int N = 1e3 + 10;
int c[N], ans[N], top = 0;
priority_queue<pii> q;
vector<int> vec[N];
inline void work(vector<int> a){
vector<pii> tmp;
for(auto x : a){
if(q.empty()){
cout << "NO" << endl;
exit(0);
}
pii now = q.top(); q.pop();
ans[x] = now.second;
tmp.push_back(make_pair(now.first - 1, now.second));
}
for(int i = 0; i < tmp.size(); i++) q.push(tmp[i]);
}
inline void solve(){
int n = 0; cin >> n;
string str; cin >> str;
for(int i = 1, x; i <= n; i++){
cin >> x; c[x]++;
}
for(int i = 1; i <= n; i++)
if(c[i]) q.push(make_pair(c[i], i));
int tot = 0;
for(auto ch : str){
if(ch == '('){
vec[top++].push_back(++tot);
vec[top].clear();
}
else work(vec[top--]);
}
work(vec[top]);
cout << "YES" << endl;
for(int i = 1; i <= n; i++) cout << ans[i] << ' ';
cout << endl;
}
signed main(){
//freopen("stdin.in", "r", stdin);
//freopen("stdout.out", "w", stdout);
ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
solve();
return 0;
}