UVA - 1205 Color a Tree

大意就是给你一颗树,每个点有一个权值w[i],求一个排列使得 所有的父亲都在儿子前面 并且排列的权值最小。

排列的权值在这里定义为 Σ i * w[p[i]]   ,其中p[i] 是排列第i个位置的元素。

然后我瞎jb胡了一个算法,对于每个子树维护一个 p[],表示只考虑子树内的元素的最优排列。显然我们只要把一个点的所有儿子都合并之后再把这个点放在排列的第一个位置就可以了。(可以证明这些元素再往上走的时候相对位置还是一样的)

问题是怎么合并。

其实这就是个dp,合并x和y子树的时候,f[i][j] 表示 用了x子树前i个元素,用了y子树前j个元素,此时到终点的最优值是多少,然后顺带记录一下方案就好啦。

(昨天+今天调了 3h+  主要是因为 fill 用了 0x7f  一直没有察觉233333,导致max一直是127(真是醉了))

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1005;
int a[maxn][maxn],n,w[maxn],f[maxn][maxn];
int to[maxn*2],ne[maxn*2],hd[maxn],num,m;
bool nxt[maxn][maxn];
inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}

inline void init(){
	memset(hd,0,sizeof(hd)),num=0;
	memset(f,0x7f,sizeof(f));
	memset(a,0,sizeof(a));
}

inline void Merge(int x,int son){
	int b[a[x][0]+a[son][0]+5],hzx[a[x][0]+5],hzs[a[son][0]+5];
    hzx[a[x][0]+1]=0;
    for(int i=a[x][0];i;i--) hzx[i]=hzx[i+1]+a[x][i];
    hzs[a[son][0]+1]=0;
    for(int i=a[son][0];i;i--) hzs[i]=hzs[i+1]+a[son][i];

    f[a[x][0]][a[son][0]]=0;
    for(int i=a[x][0];i>=0;i--)
        for(int j=a[son][0];j>=0;j--){
        	if(i<a[x][0]&&f[i+1][j]<f[i][j]) f[i][j]=f[i+1][j],nxt[i][j]=1;
        	if(j<a[son][0]&&f[i][j+1]<f[i][j]) f[i][j]=f[i][j+1],nxt[i][j]=0;
        	f[i][j]+=hzx[i+1]+hzs[j+1];
		}

	int now=0,nx=0,ny=0;
	while(++now<=a[x][0]+a[son][0]){
		if(nxt[nx][ny]) nx++,b[now]=a[x][nx];
		else ny++,b[now]=a[son][ny];
    }

	for(int i=0;i<=a[x][0];i++) fill(f[i],f[i]+a[son][0]+1,2000000000);
	a[x][0]+=a[son][0];
	for(int i=1;i<=a[x][0];i++) a[x][i]=b[i];
}

void dfs(int x,int fa){
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
		dfs(to[i],x);
		Merge(x,to[i]);
	}

	a[x][0]++;
	for(int i=a[x][0];i>1;i--) a[x][i]=a[x][i-1];
	a[x][1]=w[x];
}

inline void calc(int x){
	int ans=0;
	for(int i=1;i<=n;i++) ans+=i*a[x][i];
	printf("%d\n",ans);
}

int main(){
	int uu,vv,root;
	while(scanf("%d%d",&n,&root)==2&&n&&root){
		init();
	    for(int i=1;i<=n;i++) scanf("%d",w+i);
	    for(int i=1;i<n;i++) scanf("%d%d",&uu,&vv),add(uu,vv),add(vv,uu);
	    dfs(root,-1),calc(root);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8975757.html

时间: 2024-11-01 14:01:47

UVA - 1205 Color a Tree的相关文章

poj 2054 Color a Tree 据说是贪心

Color a Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7112   Accepted: 2438 Description Bob is very interested in the data structure of a tree. A tree is a directed graph in which a special node is singled out, called the "root&qu

UVA - 10304Optimal Binary Search Tree(递推)

题目:UVA - 10304Optimal Binary Search Tree(递推) 题目大意:给出一组数,e1 < e2 < ... < en,现在要求将这些数组成一棵二叉搜索树,并且使得sum (ei * cost(ei))最小.cost(ei)表示ei到到根节点之间有多少条边. 解题思路:首先二叉搜索树要满足左节点小于根节点,右节点大于根节点.因此对于e1 < e2 < ... < en这样一组数,我们只要枚举根节点的位置ek,将这个序列分成左右子树两部分(e

hdu 4603 Color the Tree 2013多校1-4

这道题细节真的很多 首先可以想到a和b的最优策略一定是沿着a和b在树上的链走,走到某个点停止,然后再依次占领和这个点邻接的边 所以,解决这道题的步骤如下: 预处理阶段: step 1:取任意一个点为根节点,找出父子关系并且对这个树进行dp,求出从某个节点出发往下所包含的所有边的权值总和  复杂度O(n) step 2:从tree dp 的结果中计算对于某个节点,从某条边出发所包含的边的综合,并且对其从大到小进行排序 复杂度O(n*logn) step 3:dfs求出这颗树的欧拉回路,以及每个点的

hdu 1055 &amp; poj 2054 Color a Tree 树&amp;贪心 找最大费用点和父节点合并

Color a Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 7144 Accepted: 2458 Description Bob is very interested in the data structure of a tree. A tree is a directed graph in which a special node is singled out, called the "root"

HDU 1055 Color a Tree

题目:Color a Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=1055 题意:给一棵树,要给树上每一个结点染色,第i 个结点染色需要代价为:t * w[i] (t 表示i 结点是第几个染色的),还有一个前提是:要给i 结点染色,必须先给i 结点的父结点染色(根结点随便染). 思路: 贪心. 假定当前未染色的结点中权值最大的是A结点,如果A结点上方都染完色,那么现在一定是对A结点进行染色. 理解如下: 假设在上述情况下先对其他结点染色,在

HDU1055 POJ2054 Color a Tree

Color a Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1068    Accepted Submission(s): 349 Problem Description Bob is very interested in the data structure of a tree. A tree is a directed

uva 1264 - Binary Search Tree(BST)

题目链接:uva 1264 - Binary Search Tree 题目大意:给定一个插入顺序,要求输出有多少种插入顺序,使得生成的BST一样. 解题思路:组合数学+BST的性质,起始左右两个子树的节点之间是没有影响的.所以逐层递推上去即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int max

uva 1625 - Color Length(dp 里面 L C S 问题解决方式变形)

LCS属线性结构上的动态规划,应该是动规里面很简单的一种类型. 最长公共子序列问题,一旦明确了状态,找到状态转移方程还是很简单的.但是对于本题来说,难点之一就是会很难想到该如何定义状态. 作为一只菜鸟,兹认为此题很复杂. 首先我是想不到每一步都把没到终点的字母全加上1,以及这种效果与你去找开始和结束的效果是一样的. 甚至,若不是在做动规的专题,我根本想不到这样的题目,会用动规来解决. 再一个,我想不到状态可以这么来定义"设d[ i ][ j ]表示两个序列分别已经拿出去了 i 个和 j 个元素

UVA 1264 - Binary Search Tree(BST+计数)

UVA 1264 - Binary Search Tree 题目链接 题意:给定一个序列,插入二叉排序树,问有多少中序列插入后和这个树是同样的(包含原序列) 思路:先建树,然后dfs一遍,对于一个子树而言,仅仅要保证左边和右边顺序对就能够了,所以种数为C(左右结点总数,左结点),然后依据乘法原理乘上左右子树的情况就可以 代码: #include <cstdio> #include <cstring> typedef long long ll; const int MAXNODE =