MRaZY MRain is CraZY! This is old CodeBeta.

11三/091

POJ 3719 Art of Balance

PKU某月的月赛中的一道题.写一写来练手.

题目大意是: 给出m个砝码(m<=16),有一个有n个节点的二叉树(n<=100),这棵树上有m个叶子节点,每个叶子节点可以挂上一颗砝码,一颗子树的重量是地下挂的所有砝码的重量之和,定义不平衡量为abs((lch.weight / root.weight)-1/2)*1000 , 要求给出一种方案,是的不平衡量的总和最小.

稍微想了下..m只有16..好吧...状态压缩的treedp.

记下f[root,state]为处理根为root的子树,底下用的砝码的状态为state..然后直接转移吧..

#include <stdio.h>
#include <memory.h>
 
typedef struct treenode{
	int lch,rch,count;
};
 
int cases,n,m,a[17],st[17][65538];
double f[102][65538],w[65538];
struct treenode tree[102];
 
int dfs(int root)             //统计每棵子树所包含的叶子节点的数目.
{
	if (tree[root].lch < 0 && tree[root].rch < 0) tree[root].count = 1;
	else tree[root].count += dfs(tree[root].lch) + dfs(tree[root].rch);
	return tree[root].count;
}
 
void calc_w()                //计算各种状态的重量
{
	memset(w,0,sizeof(w));
	for (int i=1; i<(1 << m); ++i)
		for (int j=0; j<m; ++j)
			if (i & (1 << j))
				w[i] += a[j+1];
}
 
void build_state(int state,int posi,int len)  //生成有用状态
{
	if (posi > 16) return;
	build_state(state,posi+1,len);
	state = state | (1 << (posi-1));
	st[++len][++st[len][0]] = state;
	build_state(state,posi+1,len);
}
 
double abs(double a)
{
	if (a < 0)
		a = -a;
	return a;
}
 
double search(int root,int state)           //DP主过程.(记忆化搜索)
{
	if (f[root][state] < 0)
	{
		f[root][state] = 2000000000;
		if (tree[root].count == 1)
		{
			f[root][state] = 0;
			return 0;
		}
		for (int i=1; i<=st[tree[tree[root].lch].count][0]; ++i)
		{
			int tstate = st[tree[tree[root].lch].count][i];
			if ((state & tstate) == tstate)
			{
				double temp = search(tree[root].lch,tstate)+search(tree[root].rch,state ^ tstate)+abs((w[tstate]/w[state])-0.5)*1000;
				if (f[root][state] > temp)
					f[root][state] = temp;
			}
		}
	}
	return f[root][state];
}
 
int main()
{
	scanf("%d",&cases);
	build_state(0,1,0);
	for (; cases; --cases)
	{
		scanf("%d",&n);
		memset(tree,0,sizeof(tree));
		for (int i=1; i<=n; ++i) scanf("%d %d",&tree[i].lch,&tree[i].rch);
		dfs(1);
		scanf("%d",&m);
		memset(a,0,sizeof(a));
		for (int i=1; i<=m; ++i) scanf("%d",&a[i]);
		calc_w();
		for (int i=1; i<=n; ++i)
			for (int j=1; j<(1 << m); ++j)
				f[i][j] = -1.0;
		printf("%.3lf\n",search(1,(1 << m)-1));
	}
}
标签: , , 发表评论
评论 (1) 引用 (0)
  1. 某月的月赛中的一道题


Leave a comment

(required)

还没有引用.