codeforces 212E VK Cup 2012 Finals (unofficial online-version) E

E. IT Restaurants

time limit per test

1.5 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

С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, yin) — 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.

Examples

input

Copy

5
1 2
2 3
3 4
4 5

output

Copy

3
1 3
2 2
3 1

input

Copy

10
1 2
2 3
3 4
5 6
6 7
7 4
8 9
9 10
10 4

output

Copy

6
1 8
2 7
3 6
6 3
7 2
8 1

Note

The figure below shows the answers to the first test case. The junctions with "iMac D0naldz" restaurants are marked red and "Burger Bing" restaurants are marked blue.

给一棵树,对于每个点可以有染红色、蓝色、不染色三种操作,红色点数为a,蓝色点数为b,并且a + b要求做大,而且a 和 b不能是相邻的节点,现在问你a和b的组合都是什么

 

首先处理出每个点下面的子树的节点个数,然后f[i][j]代表第i个节点可以达成j的个数,我们可以在树上直接跑可行性背包,知道一个点的子树节点,然后对于自己的父亲可以得到转移方程 f[x][i + n - num[x]] |= f[x][i] 

代码如下:

#include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second

using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
const int maxn = 500 + 5000;
const ll mod = 1e9 + 7;
inline int sign(db a) { return a < -eps ? -1 : a > eps;}
inline int cmp(db a,db b){ return sign(a - b);}
ll mul(ll a,ll b,ll c) { ll res = 1; while(b) {  if(b & 1) res *= a,res %= c;  a *= a,a %= c,b >>= 1;  }  return res;}
ll phi(ll x) {  ll res = x;  for(ll i = 2; i * i <= x; i++) { if(x % i == 0) res = res / i * (i - 1);   while(x % i == 0) x /= i;   }  if(x > 1) res = res / x  * (x - 1);    return res;}
int fa[maxn];
int Find(int x) {   if(x != fa[x]) return fa[x] = Find(fa[x]);  return fa[x];}
ll c,n,k;
vector<int>v[maxn];
int num[maxn];
int f[maxn][maxn];///fij代表第节点i上能否凑成j的个数
int vis[maxn];
int dfs(int x,int fa){
    num[x] = 1;
    for(auto d:v[x]){
        if(d == fa) continue;
        dfs(d,x);
        num[x] += num[d];
        for(int j = n - 1;j >= 0;j--)   if(j >= num[d])   f[x][j] |= f[x][j - num[d]];
    }
    for(int i = n - 1;i >= 0;i--)  f[x][i + n - num[x]] |= f[x][i];
    for(int i = 1;i < n;i++)   if(f[x][i]) vis[i] = 1;
}
vector<P>ans;
int main() {
    ios::sync_with_stdio(false);
    while(cin >> n){
            for(int i = 1;i <= n;i++) f[i][0] = 1;
        for(int i = 1;i < n;i++){
            int u,vv;
            cin >> u >> vv;
            v[u].push_back(vv);
            v[vv].push_back(u);
        }
        dfs(1,0);
        for(int i = 1;i < n - 1;i++){
            if(vis[i]) ans.push_back(P(i,n - 1 - i));
        }
        cout << ans.size() << endl;
        for(auto d:ans){
            cout << d.fi << " " << d.se << endl;
        }

    }
    cerr << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}
//
//6
//1 6
//5
//1 4
//2 1
//5 1
//1 3

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值