CodeForces 1362D. Johnny and Contribution

题意:约翰尼准备书写n个博客。一个博客覆盖一个主题,一个主题可以被多个博客覆盖。相邻的博客之间不能有相同的主题。约翰尼每次书写博客的时候,该博客的主题的编号必须是除了已经书写好的相邻博客的编号的集合中的最小非负整数。给定每个博客的主题,求按什么顺序书写,可以得到题目指定的主题编号?

分析:一种直观的思路是,我们先填小的数,然后再填大的数(贪心)。所以我们按结构体排序主题值,这样我们从小到大填,然后我们再判断这个填的值是否是最小非负整数(不在已经填过的相邻博客的主题集合中),这个我开了一个集合set,然后从小到大插入旁边每个节点已经填好的主题值,然后再从1开始遍历每个自然数,只要不是这个集合的,那么就是最小非负整数,有点像求SG函数的mex运算,然后如果我们题目的指定t值和这个自然数不一样,我们就输出-1。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;
using LL = long long;
const int N = 500005;
int h[N], e[N * 2], ne[N * 2], idx;
struct Node
{
	int id;
	int t;
	//按t值排序
	bool operator<(const Node& rhs)const
	{
		return t < rhs.t;
	}
}p[N];
int t[N];
int ans[N];
//标记是否填过
bool st[N];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);

	memset(h, -1, sizeof h);

	int a, b;
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d%d", &a, &b);
		add(a, b), add(b, a);
	}

	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &p[i].t);
		t[i] = p[i].t;
		p[i].id = i;
	}

	sort(p + 1, p + n + 1);

	bool flag = true;
	for (int i = 1; i <= n; ++i)
	{
		int u = p[i].id;
		//遍历相邻节点
		set<int> S;
		for (int j = h[u]; j != -1; j = ne[j])
		{
			int k = e[j];
			if (st[k])
			{
				S.insert(t[k]);
			}
		}

		for (int q = 1; ; ++q)
		{
			if (!S.count(q))
			{
				if (q != t[u])
				{
					cout << -1;
					return 0;
				}
				else
				{
					break;
				}
			}
		}
		ans[i] = u;
		st[u] = true;
	}

	for (int i = 1; i <= n; ++i)
	{
		printf("%d ", ans[i]);
	}

	return 0;
}
原文地址:https://www.cnblogs.com/pixel-Teee/p/13054950.html