洛谷P3104 Counting Friends G 题解

题目

[USACO14MAR]Counting Friends G

题解

这道题我们可以将 \((n+1)\) 个边依次去掉,然后分别判断去掉后是否能满足。注意到一点, \(n\) 个奶牛的朋友之和必定为偶数,所以去掉的那个数值的奇偶性必定与 \((n+1)\) 个数值之和的奇偶性相同。

接下来很明显的,尽量将朋友多的和朋友多的匹配,所以先从大到小排序,将第一个奶牛和后面的奶牛依次匹配,如果匹配结束,第一个奶牛还有剩余,则此情况必然不可能成立;否则匹配完之后再按照 \(O(n)\) 复杂度的归并排序给数组重新排好序。依次循环 \(n\) 次(当然如果数组中最大值已经为 \(0\) ,则直接跳出循环)。

简单说一下为什么这样做是正确的,因为奶牛无法完成匹配只可能有一种情况,就是当某一个奶牛与其他所有还可以有朋友的奶牛都匹配结束后,此奶牛依然还有剩余的朋友要匹配。所以奶牛要尽量先与朋友多的奶牛相匹配,如果先与朋友较少的奶牛匹配,则会加大朋友较多的奶牛无法完成匹配的可能性。具体严格证明应该可以用数学归纳法来证,这里就不详述了。

代码

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int n, a[502], b[500],c[500],sum=0;
	scanf("%d", &n);
	for (int i = 1; i <= n + 1; i++)
	{
		scanf("%d", &a[i]);
		sum += a[i];
	}
	int num = 0, res[501];
	for (int i = 1; i <= n + 1; i++)
	{
		if (sum % 2 != a[i] % 2)
			continue;
		int index = 0;
		for (int j = 1; j <= n + 1; j++)
			if (j != i)
				b[index++] = a[j];
		sort(b, b + n, [](const int x, const int y) {
			return x > y;
			});
		bool flag = 1;
		for (int j = 1; j <= n; j++)
		{
			if (b[0] == 0)
				break;
			int in = 1;
			while (b[0] > 0 && b[in] > 0)
			{
				b[0]--;
				b[in++]--;
			}
			if (b[0] > 0)
			{
				flag = 0;
				break;
			}
			int p = 1, q = in, cnt = 0;
			while (p < in && q < n)
				if (b[p] > b[q])
					c[cnt++] = b[p++];
				else
					c[cnt++] = b[q++];
			while (p < in)
				c[cnt++] = b[p++];
			while (q < n)
				c[cnt++] = b[q++];
			for (int k = 0; k < n - 1; k++)
				b[k] = c[k];
			b[n - 1] = 0;
		}
		if (flag)
			res[num++] = i;
	}
	printf("%d\n", num);
	for (int i = 0; i < num; i++)
		printf("%d\n", res[i]);
	return 0;
}
posted @ 2021-08-17 09:41  反演的莫比乌斯环  阅读(70)  评论(0)    收藏  举报