国王的宴会

Description

C国在成果破解J国破坏交通的阴谋之后,国王决定宴请各位大臣,合理制定宴请的人的名单的任务就交给了作为国王智囊团团长的你。

你知道国王喜欢热闹,所以你希望能邀请尽量多的人,但是做为直接上下级关系的两个人直接出现在宴会上的时候会显得很尴尬,所以不能同时请有上下级关系的两个人。

国王是宴会的主办方,也是这个王国的最高领袖,所以必须到场。

为了能为宴会准备的更好,你需要知道整个宴会最多可以邀请多少宾客。

Input

有多组测试数据。

每组数据的第一行两个整数n(n<=1000)m分别表示整个王国的官员的数量和上下级关系的数量。

接下来m行每行两个整数ab表示ba的直接下级。

处理到文件结束。

Output

输出一个整数表示包括国王在内的宴会能邀请的人数最多的数量。

Sample Input

5 4

5 3

3 4

4 1

4 2

Sample Output

3

题目意思为国王要举行宴会,他想邀请尽可能多的人来参加,但是上下级的关系的人不能同时参加。很显然题目给的是一颗以国王为根的树,要求国王必须参加,然后选尽可能多的节点,我们可以用树形dp来求解,因为没个节点有两个状态,去或者不去,而父亲节点可以根据子节点的状态来确定状态,我们可以开一个二维dp数组,dp[1001][3],其中dp[i][0]表示i节点不去,dp[i][1]表示i节点去参加,这样我们可以确定两种状态下的最大值,并且得出状态转移方程

如果当前结点去参加,则儿子节点肯定不能去,dp[root][1] += dp[to][0];其中root为当前结点,to为儿子节点

如果当前结点不参加,儿子节点有两种状态,可以去也可以不去,所以dp[root][0] += max(dp[to][1], dp[to][0]);

知道状态转移方程之后,我们采用dfs的方法来进行dp

代码如下:

#include<stdio.h>
#include<iostream>
#include<vector>
#include<string.h>
using namespace std;
const int maxn = 1000 + 10;
vector<int>t[maxn];
int dp[maxn][3], vis[maxn], in_deg[maxn];
void dfs(int root)
{
    dp[root][1] = 1;
    dp[root][0] = 0;
    vis[root] = 1;
    for(int i = 0; i < t[root].size(); ++ i)
    {
        int to = t[root][i];
        if(vis[to]) continue;
        dfs(to);
        dp[root][1] += dp[to][0];
        dp[root][0] += max(dp[to][1], dp[to][0]);
    }
}
int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        for(int i = 0; i < maxn; ++ i)
        {
            t[i].clear();
        }
        memset(dp, 0, sizeof(dp));
        memset(in_deg, 0, sizeof(in_deg));
        memset(vis, 0, sizeof(vis));
        for(int i = 0; i < m; ++ i)
        {
            int a, b;
            cin >> a >> b;
            t[a].push_back(b);
            in_deg[b]++;
        }
        int root;
        for(int i = 1; i <= n; ++ i)
        {
            if(in_deg[i] == 0)
            {
                root = i;
                break;
            }
        }
        dfs(root);
        int ans = dp[root][1];
        cout << ans << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值