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];
mapmp;
map::iterator it;


bool dfs(map::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;
}



你可能感兴趣的:(其他——思维训练)