【POJ 1947】Rebuilding Roads(树型DP)
2016-03-22 16:45
495 查看
【POJ 1947】Rebuilding Roads(树型DP)
Description
The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The cows didn't have time to rebuild any extra roads, so now there is exactly one way to get
from any given barn to any other barn. Thus, the farm transportation system can be represented as a tree.
Farmer John wants to know how much damage another earthquake could do. He wants to know the minimum number of roads whose destruction would isolate a subtree of exactly P (1 <= P <= N) barns from the rest of the barns.
Input
* Line 1: Two integers, N and P
* Lines 2..N: N-1 lines, each with two integers I and J. Node I is node J's parent in the tree of roads.
Output
A single line containing the integer that is the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated.
Sample Input
Sample Output
Hint
[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.]
Source
USACO 2002 February
卡了一阵子……只能说对树型dp的理解还不是非常深刻……
题目大意:一棵树,问最少砍几条边,能得到一个p个节点的子树。
这样可以想到用dp[i][j]表示节点i为根,得到j个节点的子树所需要砍掉的最少边数。
这样对于父节点u,遍历孩子节点v1.2.3...时,每当新加一个子节点v,可以选取v中0.1.2.3....k(k <= v子树的节点数) 这样对于dp[u][i] 可以通过dp[u][j]外加从v中选取的节点(i-j个)来组成,也就是转移方程。
如果上面的想明白了,会发现有新的问题,dp[i][j]表示以i为根的j个节点的子树所砍掉的边数,但不能包含i和其父亲(如果i不是根)的边,否则在遍历i的父亲那层中会导致转移出错,因为在这层,它与i之间的边不可砍掉(除非整个i子树都不选取)。所以我的方法就是做了一堆啰嗦的判断……
大体这样取个最小值就行了,要注意p个节点的子树可以以原树中任何一个节点为根,也就是答案要在遍历的过程中找。
代码如下:
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 10607 | Accepted: 4863 |
The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The cows didn't have time to rebuild any extra roads, so now there is exactly one way to get
from any given barn to any other barn. Thus, the farm transportation system can be represented as a tree.
Farmer John wants to know how much damage another earthquake could do. He wants to know the minimum number of roads whose destruction would isolate a subtree of exactly P (1 <= P <= N) barns from the rest of the barns.
Input
* Line 1: Two integers, N and P
* Lines 2..N: N-1 lines, each with two integers I and J. Node I is node J's parent in the tree of roads.
Output
A single line containing the integer that is the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated.
Sample Input
11 6 1 2 1 3 1 4 1 5 2 6 2 7 2 8 4 9 4 10 4 11
Sample Output
2
Hint
[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.]
Source
USACO 2002 February
卡了一阵子……只能说对树型dp的理解还不是非常深刻……
题目大意:一棵树,问最少砍几条边,能得到一个p个节点的子树。
这样可以想到用dp[i][j]表示节点i为根,得到j个节点的子树所需要砍掉的最少边数。
这样对于父节点u,遍历孩子节点v1.2.3...时,每当新加一个子节点v,可以选取v中0.1.2.3....k(k <= v子树的节点数) 这样对于dp[u][i] 可以通过dp[u][j]外加从v中选取的节点(i-j个)来组成,也就是转移方程。
如果上面的想明白了,会发现有新的问题,dp[i][j]表示以i为根的j个节点的子树所砍掉的边数,但不能包含i和其父亲(如果i不是根)的边,否则在遍历i的父亲那层中会导致转移出错,因为在这层,它与i之间的边不可砍掉(除非整个i子树都不选取)。所以我的方法就是做了一堆啰嗦的判断……
大体这样取个最小值就行了,要注意p个节点的子树可以以原树中任何一个节点为根,也就是答案要在遍历的过程中找。
代码如下:
#include <iostream> #include <cmath> #include <vector> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <stack> #include <list> #include <algorithm> #include <map> #include <set> #define LL long long #define Pr pair<int,int> #define fread() freopen("in.in","r",stdin) #define fwrite() freopen("out.out","w",stdout) using namespace std; const int INF = 0x3f3f3f3f; const int msz = 10000; const int mod = 1e9+7; const double eps = 1e-8; bool can[155][155]; int dp[155][155]; int n,p,mn; void dfs(int u) { memset(dp[u],INF,sizeof(int)*n); dp[u][0] = dp[u][1] = 0; bool f = 0; for(int i = 1; i <= n; ++i) { if(!can[u][i]) continue; f = 1; dfs(i); for(int k = p; k >= 1; --k) { if(dp[u][k] != INF) dp[u][k]++; for(int j = 1; j <= p && j < k && dp[i][j] != INF; ++j) { if(dp[u][k-j] != INF) dp[u][k] = min(dp[u][k-j]+dp[i][j],dp[u][k]); } } } //如果u不是整个树的根,那么在dp数组中不计入其与父节点的边(为了方便转移),在取答案时需要加上(断绝它与父节点的联系) if(u != 1) mn = min(mn,dp[u][p]+1); else mn = min(mn,dp[u][p]); } int main() { //fread(); //fwrite(); int u,v; while(~scanf("%d%d",&n,&p)) { memset(can,0,sizeof(can)); for(int i = 1; i < n; ++i) { scanf("%d%d",&u,&v); can[u][v] = 1; } mn = INF; dfs(1); printf("%d\n",mn); } return 0; }
相关文章推荐
- UIImagePickerController从拍照、图库、相册获取图片
- 应用Druid监控SQL语句的执行情况
- 在使用xib自定UIView时里面的tableView不显示问题
- mysql连接池-druid
- easyui日期控件开始日期小于结束日期
- UE4 引擎 package 可执行文件过程中碰到fatal error的常见解决方法
- Java之序列流SequenceInputStream
- UIMenuController使用
- UIPasteboard 粘贴板
- iOS开发中设置UITableViewCell选中时的颜色
- hdu1711 Number Sequence 求模式串在主串中的位置
- 开关控件 UISwitch
- Building Android Kernel for the Nexus 5 — AOSP(6.0.1)
- 在ios7及以上系统中在UINavigationBar中添加UITextField或者UISearchbar时不显示输入光杆问题及解决
- 多个模型 在 tableview
- UISegmentedControl UISlider
- UIButton中setTitleEdgeInsets和setImageEdgeInsets的使用
- uiui
- [Leetcode]Binary Tree Longest Consecutive Sequence
- No 'Access-Control-Allow-Origin' header is present on the requested resource