POJ 1947--Rebuilding Roads
来源:互联网 发布:封面制作软件下载 编辑:程序博客网 时间:2024/06/06 22:59
题意:给定一规模为N的树,问至少去掉多少条边能得到一个规模为P的子树。
题解:看了一些大牛的题解,很困惑纠结一些问题。
- 最佳答案是否是包括整棵树根节点的一颗子树,
- 动态规划定义时的状态是否是包括子树根节点的解。
对于第一个可以很容易举出反例:
4 1
1 2
1 4
2 3
其代价为1的子树只含有节点3,不包括根节点1。所以最佳子树不一定包括整棵树根节点。
对于第二个问题,直接用动态规划说明。
- 设dp[i][fa][j]为计算到fa的第i个子节点为止产生规模为j的子树的至少需要摧毁的边。这里规模为j的子树是包括节点fa的。
- 转移方程:对于计算到fa的第i个子节点sons[fa][i]的每个j状态可由计算到第fa的第i-1个子节点sons[fa][i-1]的状态求得,dp[i][fa][j] = min{min{dp[i-1][fa][k]+dp[M][sons[fa][i-1]][j-k],0 <= k <= j},dp[i-1][fa][j]+1}。其中M为sons[fa][i-1]的子节点数目。其中前一个比较基于计算到第i个子节点为止的最佳子树包括第i个子节点sons[fa][i],所以枚举可能的规模,第二个比较基于不包括sons[fa][i],所以需要在已经计算的摧毁边上再加一。
- dp数组可以使用滚动数组,去除第一维,但是求枚举状态j的必须用倒序,这样才能使数组使用时不被更新为第i个子节点的新状态。
- 初始化:dp[fa][1] = 0,dp[fa][0] = 1。
#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;#define INF 0X3F3F3F3Fclass solve{private: vector<vector<int> > sons; char* vis; int** dp; int N,P; int root; int minCost; int minRoot;public: solve(int n,int p):N(n),P(p) { sons.resize(N+1); vis = new char[N+1]; memset(vis,0,sizeof(char)*(N+1)); dp = new int*[N+1]; minCost = INF; for(int i = 1;i <= N;i++) { dp[i] = new int[N+1]; memset(dp[i],0X3F,sizeof(int)*(N+1)); dp[i][1] = 0; dp[i][0] = 1; } processIn(); for(int i = 1;i <= N;i++) { if(!vis[i]) //直到遍历完整棵树 { root = i; //最后进入的根节点必定是整棵树的根节点 DFS(i); } } if(minRoot != root) //如果最小的代价不是以根节点为根的子树,还要加上其与父节点链接的道路需要摧毁 { minCost++; } printf("%d\n",minCost); } ~solve() { vector<vector<int> >().swap(sons); delete[] vis; delete[] dp; } int processIn(); int DFS(int fa);};int solve::DFS(int fa){ vis[fa] = 1; int sonSize = sons[fa].size(); int tmpMin; for(int i = 0;i < sonSize;i++) { int son = sons[fa][i]; if(!vis[son]) { DFS(son); } for(int j = P;j >= 1;j--) //滚动数组倒序DP,利用上一个子节点DP产生的数据 { tmpMin = INF; for(int k = 0;k <= j;k++) { tmpMin = min(dp[fa][k]+dp[son][j-k],tmpMin); } dp[fa][j] = min(dp[fa][j]+1,tmpMin); } dp[fa][0] = dp[fa][1]+1; } if(minCost >= dp[fa][P]) //需要加上等号,因为要根节点优先,结果可能有1差距 { minCost = dp[fa][P]; minRoot = fa; } return 0;}int solve::processIn(){ int fa,son; for(int i = 1;i < N;i++) { scanf("%d%d",&fa,&son); sons[fa].push_back(son); } return 0;}int main(){ int n,p; while(~scanf("%d%d",&n,&p)) { solve poj_1947(n,p); } return 0;}
0 0
- POJ 1947 Rebuilding Roads
- poj 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- poj 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- poj-1947-Rebuilding Roads
- POJ 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- POJ 1947 Rebuilding Roads
- POJ 1947--Rebuilding Roads
- POJ 1947 Rebuilding Roads
- poj-1947 Rebuilding Roads
- Poj 1947 Rebuilding Roads
- POJ 1947 Rebuilding roads
- 【poj 1947】 Rebuilding Roads
- 国外程序员推荐:每个程序员都应读的书
- java native2ascii的用法介绍
- 装饰模式
- HBase总结(十四)LINUX下用Eclipse构建HBase开发环境
- mac下安装 php mongo redis 扩展
- POJ 1947--Rebuilding Roads
- c++类模版和运算符重载的运用
- Linux下C++的的开发和调试运行工具
- HBase总结(十八)Hbase rowkey设计一
- ExtJs开发-入门篇
- 用bootstrap实现表格隔行变色,hover 变色并在需要时出现滚动条
- Activty与Service通信的所有情况(相同进程、不同进程)
- MySQL数据库引擎介绍、区别、创建和性能测试的深入分析
- WP_Query的使用方法