Description
C国在成果破解J国破坏交通的阴谋之后,国王决定宴请各位大臣,合理制定宴请的人的名单的任务就交给了作为国王智囊团团长的你。
你知道国王喜欢热闹,所以你希望能邀请尽量多的人,但是做为直接上下级关系的两个人直接出现在宴会上的时候会显得很尴尬,所以不能同时请有上下级关系的两个人。
国王是宴会的主办方,也是这个王国的最高领袖,所以必须到场。
为了能为宴会准备的更好,你需要知道整个宴会最多可以邀请多少宾客。
Input
有多组测试数据。
每组数据的第一行两个整数n(n<=1000)和m分别表示整个王国的官员的数量和上下级关系的数量。
接下来m行每行两个整数a和b表示b是a的直接下级。
处理到文件结束。
Output
输出一个整数表示包括国王在内的宴会能邀请的人数最多的数量。
Sample Input
5 4
5 3
3 4
4 1
4 2
Sample Output
题目意思为国王要举行宴会,他想邀请尽可能多的人来参加,但是上下级的关系的人不能同时参加。很显然题目给的是一颗以国王为根的树,要求国王必须参加,然后选尽可能多的节点,我们可以用树形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; }