poj 1655 树状dp

来源:互联网 发布:淘宝修改论文靠谱吗 编辑:程序博客网 时间:2024/06/18 17:53
#include<iostream>#include<cstdio>#include<string.h>#include<cstring>#include<string>#include<algorithm>using namespace std;const int maxn = 20010;const int inf = 0x1fffffff;typedef struct EDGE{int node,Next;}Edge;Edge edge[maxn<<1];int balance[maxn],recordnode[maxn],nodenum[maxn],t,n;bool visit[maxn];int cntEdge = 0;inline void addEdge(int n1,int n2){edge[cntEdge].node = n1; edge[cntEdge].Next = recordnode[n2]; recordnode[n2] = cntEdge++;edge[cntEdge].node = n2; edge[cntEdge].Next = recordnode[n1]; recordnode[n1] = cntEdge++;}int dfs(int id){int ans = 0, sum = 0,i;visit[id] = 1;for(i = recordnode[id]; i != -1; i = edge[i].Next){int nodeid = edge[i].node;if(!visit[nodeid]){    int t = dfs(nodeid);sum += t;if(ans < t)ans = t;}}//ans为以id的所有叶结点为根的子树所含结点的最大值nodenum[id] = sum + 1;int t = n - nodenum[id];  //删掉以id为根的子树后余下的所有结点if(ans < t){ans = t;}balance[id] = ans;return nodenum[id];}int main(){int i;scanf("%d",&t);while(t--){scanf("%d",&n);cntEdge = 0;memset(visit,0,sizeof(visit));memset(nodenum,0,sizeof(nodenum));memset(recordnode,-1,sizeof(recordnode));int node1,node2;for(i = 1; i < n; ++i){scanf("%d%d",&node1,&node2);addEdge(node1,node2);}dfs(1);int ans,index = -1;bool ismax;ans = inf;for(i = 1; i <= n; ++i){ismax = ans > balance[i];ans = ismax?balance[i]:ans;index = ismax?i:index;}printf("%d %d\n",index,ans);}return 0;}

题目大意:

给定一颗树,对每个结点,其balance为去掉这个结点后产生的森林中各个子树的最大节点数,求所有节点中balance值最小的那个

解题思路:

设n为树中的结点总数,num[i]表示以结点i为根结点的子树的节点数

balance[k] = max(n-num[k],num[j1],num[j2]...num[jl])(j1,j2,...,jl是k的所有子树编号)

因为题目中给定的边的顺序未必是树的构建顺序,所以要用dfs+标记visit的方法来确定树中的根和子结点的关系

0 0
原创粉丝点击