首页 > 代码库 > Codeforces Round #245 (Div. 1)——Guess the Tree

Codeforces Round #245 (Div. 1)——Guess the Tree

题目链接

  • 题意:
    n个节点,给定每一个节点的子树(包含自己)的节点个数。每一个节点假设有子节点必定大于等于2。求这种数是否存在
    n (1?≤?n?≤?24).
  • 分析:

  • 用类似DP的思路,从已知開始。这题的已知显然是叶子,那么从叶子開始考虑。

    如今给一个节点,子树节点数为x。那么从叶子中找x-1个就可以。之后再来一个y。不放设y <= x,这时候就有两种选择,尽量选1或者尽量选x。分析一下:首先明确一点。无论怎样选择,之后能用的点的和是一定的。假设尽量选小的,那么会使得选过之后的点数小的比較少。假设尽量选大的,那么之后的点数的方差比較大(表述比較抽象。事实上就是大的更大。小的还在),那么显然尽量选大的是最好的

    后来发现有些瑕疵,尽量选大的可能会导致当前点无解,比方1 1 1 1 1 1 1 4 3 3 7 12这个数据
    所以在选择的时候,贪心选择,假设无解再回溯就可以

const int MAXN = 50;

struct Node
{
	int x;
	Node (int x) : x(x) {}
	bool operator< (const Node& rhs) const
	{
		return x > rhs.x;
	}
};
int ipt[MAXN];
map<Node, int>mp;
map<Node, int>::iterator it;


bool dfs(map<Node, int>::iterator it, int& v)
{
	if (it == mp.end())
	{
		if (v == 0) return true;
		return false;
	}
	int n = it->first.x;
	int num = min(v / n, it->second);
	FED(i, num, 0)
	{
		it->second -= i;
		v -= i * n;
		if (dfs(++it, v))
			return true;
		v += i * n;
		it--;
		it->second += i;
	}
	return false;
}

int main()
{
	//    freopen("in.txt", "r", stdin);
	int n;
	while (~RI(n))
	{
		mp.clear();
		bool ok = true;
		int cnt = 0;
		REP(i, n)
		{
			int t;
			RI(t);
			if (t == 1) mp[Node(t)]++;
			else ipt[cnt++] = t;
		}
		sort(ipt, ipt + cnt);
		REP(i, cnt)
		{
			int t = ipt[i] - 1;
			it = mp.upper_bound(Node(t));
			if (!dfs(it, t))
			{
				ok = false;
				break;
			}
			it = mp.begin();
			while (it != mp.end())
			{
				if (it->second == 0)
					mp.erase(it++);
				else
					it++;
			}
			mp[Node(ipt[i])]++;
		}
		if (mp.size() != 1 || mp.begin()->second != 1) ok = false;
		if (ok) puts("YES");
		else puts("NO");
	}
	return 0;
}



Codeforces Round #245 (Div. 1)——Guess the Tree