2021牛客多校10F Train Wreck (贪心,思维题)

题意,给一个堆,只支持push和pop,有n个点,每个点都有颜色(可能相同可能不同),现给出push和pop的顺序,让你分别push时放入哪个点,保证此次push后点组成的颜色序列与之前某次push后形成的颜色序列不同
如果我们将push当作是创建一个新节点,pop是回溯到上一个节点的话,我们很容易将序列
入 入 出 入 出 出 入 出
构建成一棵树
请添加图片描述

进过观察可发现,如果仅2,3的颜色相同:
设1号颜色为红,23号为橙,4号为黄
入 红
入 红橙
出 红
入 红橙
出 红

入 黄

可以看到第二行的序列和第4行的两个的序列出现相同
同理,如果1,4颜色相同,也会出现冲突,
而若12颜色相同,
入 红
入 红 红
出 红
入 红橙
出 红
w出
入 黄

没有一个入序列相同(注意,题目中说的是入序列)
13颜色相同,24颜色相同则不会出现冲突
观察这些点在树中的位置,不难发现当任意两个颜色相同的点被同一个父节点连接时,该情况不成立
所以我们要保证任意一个节点下所有点的所有儿子的颜色不同颜色的数量有多有少,所以我们应该优先选择那些数量多的颜色,以保证颜色种类的多样性
如果当一个节点子节点数量多于当前可选颜色的种类,就说明本问题无解
我们可以用两次dfs,第一次dfs用于建立这棵树,第二次dfs用于遍历每个节点,给其子节点赋颜色
(还有一种写法不用建树的写法,但我感觉这种写法很难理解)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
vector<int>g[N];
int n;
int sum[N];
priority_queue < pair<int, int>> q;//第一个储存颜色数量,第二个储存编号
int ans[N];
string c;
int idx=0, cnt=0;

void dfs1(int now, int fa) {
    
    
	if(idx==2*n-1)return ;
	if (c[idx++] == '(') {
    
    
		g[fa].push_back(++cnt);
		dfs1(now+1, now);
	} else {
    
    
		dfs1(fa,fa-1);
	}
}

void dfs2(int now) {
    
    
	vector<pair<int, int>>cp;
	for (auto i : g[now]) {
    
    
		if (!q.size()) {
    
    
			cout << "NO" << endl;
			exit(0);
		}
		auto t = q.top();
		q.pop();
		ans[i] = t.second;
		cp.push_back({
    
    t.first - 1, t.second});
	}
	for (auto i : cp) {
    
    
		q.push({
    
    i});
	}
	for (auto i : g[now]) {
    
    
		dfs2(i);
	}
}

int main() {
    
    
	cin >> n;
	cin>>c;
	for (int i = 1; i <= n; i++) {
    
    
		int k;
		cin >> k;
		sum[k]++;
	}
	for (int i = 1; i <= n; i++) {
    
    
		if (sum[i] > 0)
			q.push({
    
    sum[i], i});
	}
	dfs1(1, 0);
	dfs2(0);
	cout << "YES" << endl;
	for (int i = 1; i <= n; i++) {
    
    
		cout << ans[i] << " ";
	}
	cout << endl;
	return 0;
}

这是不用建树的写法,g[i]代表当前搜索的路径上,层次相同的点是哪些

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int num[N];
vector<int>g[N];//g[i]记录在当前子节点下,第i层有哪些节点
priority_queue < pair<int, int>> q;
int n, ans[N];
char s[N * 2];
int cnt, top;

void calc(vector<int>a) {
    
    
	vector<pair<int, int>>cp;
	for (auto x : a) {
    
    
		if (q.empty()) {
    
    
			//由于要保证,在一次calc中所选的颜色各不相同,当q为空,说明颜色种类不够用了
			cout << "NO" << endl;
			exit(0);
		}
		auto t = q.top();
		q.pop();
		ans[x] = t.second;
		cp.push_back({
    
    t.first - 1, t.second});
	}
	for (auto i : cp) {
    
    
		q.push(i);//把取出后减一的状态储存回去
	}
}

int main() {
    
    
	cin >> n;
	scanf("%s", s + 1);
	for (int i = 1; i <= n; i++) {
    
    
		int k;
		scanf("%d", &k);
		num[k]++;
	}
	for (int i = 1; i <= n; i++) {
    
    
		if (num[i] > 0)
			q.push({
    
    num[i], i});
	}
	for (int i = 1; i <= 2 * n; i++) {
    
    
		if (s[i] == '(') {
    
    
			g[top++].push_back(++cnt);
			g[top].clear();
		} else {
    
    
			calc(g[top--]);
		}
	}
	calc(g[top]);
	puts("YES");
	for (int i = 1; i <= n; i++) {
    
    
		printf("%d%c", ans[i], i == n ? '\n' : ' ');
	}

}


猜你喜欢

转载自blog.csdn.net/fdxgcw/article/details/119754590