【CF212E】IT Restaurants (01背包问题)

题目概述

Сity N. has a huge problem with roads, food and IT-infrastructure. In total the city has n junctions, some pairs of them are connected by bidirectional roads. The road network consists of n - 1 roads, you can get from any junction to any other one by these roads. Yes, you’re right — the road network forms an undirected tree.

Recently, the Mayor came up with a way that eliminates the problems with the food and the IT-infrastructure at the same time! He decided to put at the city junctions restaurants of two well-known cafe networks for IT professionals: “iMac D0naldz” and “Burger Bing”. Since the network owners are not friends, it is strictly prohibited to place two restaurants of different networks on neighboring junctions. There are other requirements. Here’s the full list:

each junction must have at most one restaurant;
each restaurant belongs either to “iMac D0naldz”, or to “Burger Bing”;
each network should build at least one restaurant;
there is no pair of junctions that are connected by a road and contains restaurants of different networks.
The Mayor is going to take a large tax from each restaurant, so he is interested in making the total number of the restaurants as large as possible.

Help the Mayor to analyze the situation. Find all such pairs of (a, b) that a restaurants can belong to “iMac D0naldz”, b restaurants can belong to “Burger Bing”, and the sum of a + b is as large as possible.

Input
The first input line contains integer n (3 ≤ n ≤ 5000) — the number of junctions in the city. Next n - 1 lines list all roads one per line. Each road is given as a pair of integers xi, yi (1 ≤ xi, yi ≤ n) — the indexes of connected junctions. Consider the junctions indexed from 1 to n.

It is guaranteed that the given road network is represented by an undirected tree with n vertexes.

Output
Print on the first line integer z — the number of sought pairs. Then print all sought pairs (a, b) in the order of increasing of the first component a.

题目链接

传送门

分析

在这里插入图片描述
给你一棵树,对于每个节点,要么染红色,要么染蓝色,要么不染色,且红色蓝色都至少有1个,问两种颜色的和最大是多少。很容易想到只有一个点不染色,最大的 a + b的值为n - 1。我们可以枚举每一个不染色的节点,转化为一个01背包问题。用子树的大小作为价值,res[i] = 1表示存在某种取法,使得子树的大小之和为i。最后由于红蓝至少都有一个,我们从2到n - 2枚举答案。注意每次dp都要初始化。

代码

#include <iostream>
#include <cstring>
#include <cctype>
 
using namespace std;
const int N = 5005;
int n, cnt;
int dp[N], res[N],size[N], head[N];
struct edge{
    int to, nxt;
}e[N << 1];
 
inline int read(){
    int x = 0, op = 1;
    char ch = getchar();
    while (!isdigit(ch)){
        if (ch == '-') op = -1;
        ch = getchar();
    }
    while (isdigit(ch)){
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * op;
}
 
inline void add(int u, int v){
    e[++cnt] = {v, head[u]};
    head[u] = cnt;
}
 
void dfs(int u, int fa){
    size[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v, u);
        size[u] += size[v];
    }
}
 
int main() {
    n = read();
    for (int i = 1, x, y; i <= n - 1; ++i) {
        x = read(), y =read();
        add(x, y), add(y, x);
    }
    
    for (int i = 1; i <= n; ++i) {
        memset(size, 0, sizeof (size));
        memset(dp, 0, sizeof (dp));
        dfs(i, -1);
 
        dp[0] = 1;
        for (int j = head[i]; j; j = e[j].nxt) {
            int num = size[e[j].to];
            for (int k = n; k >= num; k--) {
                if (dp[k - num])
                    dp[k] = res[k] = 1;
            }
        }
    }
 
    int count = 0;
    for (int i = 1; i <= n - 2; ++i) {
        if (res[i])
            count++;
    }
    printf("%d\n", count);
    for (int i = 1; i <= n - 2; ++i) {
        if (res[i])
            printf("%d %d\n", i, n - 1 - i);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值