洛谷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;
}

浙公网安备 33010602011771号