BZOJ 1785 [Usaco2010 Jan]telephone

BZOJ_1785

    一开始没有什么直接的思路,不过由于是棵树,而且K很小,也许是个树形的dp或者背包什么的,不过后来仔细一想,其实可以用贪心解决问题的。

    对于一个非叶子节点,假设其若干子树中还有一些未配对的奶牛,那么应该是优先这些子树之间相互配对的,因为如果两个子树之间的两头奶牛可以配对但没有配对,而是有一个奶牛通过父亲甚至祖先和另外的奶牛配对了,这样不仅占有了当前这个节点的交换机的资源,还多占用了其父亲甚至祖先节点的交换机的资源,这样显然是划不来的。所以如果子树的奶牛之间可以相互配对,那么自然就先配好,剩下的奶牛再通过父节点传递出去。

    大体的思路形成了,但不难发现还有一个小细节,一棵子树中可以有多个奶牛未配对吗?其实至多只会有一个奶牛配对,因为如果在满足交换机容量限制的前提下出现多个奶牛未配对,那么它们一定可以在子树中的某个交换机上就可以实现配对了。

    我的程序里面f[i]表示的是当前一共完成了多少个配对,g[i]表示这个节点是否还剩余了1头奶牛尚未配对。

#include<stdio.h>
#include<string.h>
#define MAXD 100010
#define MAXM 200010
int N, K, D, first[MAXD], e, next[MAXM], v[MAXM], f[MAXD], g[MAXD];
void add(int x, int y)
{
    v[e] = y;
    next[e] = first[x], first[x] = e ++;
}
void init()
{
    memset(first, -1, sizeof(first[0]) * (N + 1)), e = 0;
    D = 0;
    for(int i = 1; i < N; i ++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y), add(y, x);
        if(x == 1 || y == 1) ++ D;
    }
}
void dfs(int cur, int fa)
{
    int flag = 0;
    f[cur] = 0, g[cur] = 0;
    for(int i = first[cur]; i != -1; i = next[i])
        if(v[i] != fa)
        {
            flag = 1;
            dfs(v[i], cur);
            f[cur] += f[v[i]], g[cur] += g[v[i]];
        }
    if(flag == 0) g[cur] = 1;
    else
    {
        if(g[cur] > 2 * K) f[cur] += K, g[cur] = 0;
        else f[cur] += g[cur] / 2, g[cur] &= 1;
    }
}
void solve()
{
    dfs(1, -1);
    if(D == 1 && g[1]) ++ f[1];
    printf("%d\n", f[1]);
}
int main()
{
    while(scanf("%d%d", &N, &K) == 2)
    {
        init();
        if(N == 1) printf("0\n");
        else solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/staginner/p/2740458.html