HDU6178-Monkeys

来源:互联网 发布:矩阵论引论课后答案 编辑:程序博客网 时间:2024/06/08 10:58

Monkeys

                                                                    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 153428/153428 K (Java/Others)
                                                                                            Total Submission(s): 1050    Accepted Submission(s): 354


Problem Description
There is a tree having N vertices. In the tree there are K monkeys (K <= N). A vertex can be occupied by at most one monkey. They want to remove some edges and leave minimum edges, but each monkey must be connected to at least one other monkey through the remaining edges.
Print the minimum possible number of remaining edges.
 

Input
The first line contains an integer T (1 <= T <= 100), the number of test cases. 
Each test case begins with a line containing two integers N and K (2 <= K <= N <= 100000). The second line contains N-1 space-separated integers a1,a2,,aN1, it means that there is an edge between vertex ai and vertex i+1 (1 <= ai <= i).
 

Output
For each test case, print the minimum possible number of remaining edges.
 

Sample Input
24 41 2 34 31 1 1
 

Sample Output
22
 

Source
2017 Multi-University Training Contest - Team 10
 


题意:给你一棵n个点的树,现在有k只猴子,砍尽可能多的边,使得这K只猴子分部在若干个联通块中们(在同一个联通块中,至少有两只猴子)输出剩下的最少的边数。

解题思路:砍掉尽可能多的边,所以必然是尽可能多的两两相连的小联通块(只用一条边去连接),很显然是需要跑最大二分匹配数,但匈牙利匹配显然不行,所以dfs扫一遍用树形dp来做或点之间两两标记来做


树形dp:


#include <iostream>  #include <cstdio>  #include <string>  #include <cstring>  #include <algorithm>  #include <queue>  #include <vector>  #include <set>  #include <stack>  #include <map>  #include <climits>  #include <functional>  using namespace std;#define LL long long  const int INF = 0x3f3f3f3f;inline char get(){    static char buf[100000], *p1 = buf, *p2 = buf;    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;}template <class T> inline bool read(T & x){    char ch = get();    if (ch == EOF) return false;    while (ch<'0' || ch>'9') ch = get();    x = ch - '0';    while ((ch = get()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';    return true;}int s[100009], nt[200009], e[200009];int dp[100009][2],n,ans,k;void dfs(int x, int pre){    dp[x][1]++;    for (int i = s[x]; i != -1; i = nt[i])    {        int ee = e[i];        if (ee == pre) continue;        dfs(ee, x);        dp[x][1] += min(dp[ee][0], dp[ee][1]);        dp[x][0] += dp[ee][1];    }}int main(){    int t;    read(t);    while (t--)    {        read(n), read(k);        memset(dp, 0, sizeof dp);        memset(s, -1, sizeof s);        int a, cnt = 0;        for (int i = 2; i<=n; i++)        {            read(a);            nt[++cnt] = s[i], s[i] = cnt, e[cnt] = a;            nt[++cnt] = s[a], s[a] = cnt, e[cnt] = i;        }        dfs(1, 1);        ans = min(dp[1][0], dp[1][1]);        if (ans * 2 >= k)        {            ans = k / 2;            if (k & 1) ans++;            printf("%d\n", ans);        }        else        {            ans = k - 2 * ans + ans;            printf("%d\n", ans);        }    }    return 0;}


标记法:


#include <iostream>  #include <cstdio>  #include <string>  #include <cstring>  #include <algorithm>  #include <queue>  #include <vector>  #include <set>  #include <stack>  #include <map>  #include <climits>  #include <functional>  using namespace std;#define LL long long  const int INF = 0x3f3f3f3f;inline char get(){    static char buf[100000], *p1 = buf, *p2 = buf;    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;}template <class T> inline bool read(T & x){    char ch = get();    if (ch == EOF) return false;    while (ch<'0' || ch>'9') ch = get();    x = ch - '0';    while ((ch = get()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';    return true;}int n, k, cnt, a, ans;int s[100009], nt[200009], e[200009],vis[100009];void dfs(int k, int fa){    for (int i = s[k]; ~i; i = nt[i])    {        if (e[i] == fa) continue;        dfs(e[i], k);        if (!vis[k] && !vis[e[i]])        {            vis[e[i]] = vis[k] = 1;            ans++;        }    }}int main(){    int t;    read(t);    while (t--)    {        read(n), read(k);        cnt = ans = 0;        memset(s, -1, sizeof s);        memset(vis, 0, sizeof vis);        for (int i = 2; i <= n; i++)        {            read(a);            nt[cnt] = s[i], s[i] = cnt, e[cnt++] = a;            nt[cnt] = s[a], s[a] = cnt, e[cnt++] = i;        }        dfs(1, 1);        if (ans * 2 >= k)        {            ans = k / 2;            if (k & 1) ans++;            printf("%d\n", ans);        }        else        {            ans = k - ans * 2 + ans;            printf("%d\n", ans);        }    }    return 0;}

原创粉丝点击