码迷,mamicode.com
首页 > 其他好文 > 详细

HDU ACM 4044 GeoDefense ->树形DP+分组背包

时间:2015-05-13 19:52:34      阅读:309      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   编程   

题意:地图是一个编号为1~n的节点的树,节点1是敌方基地,其他叶节点是我方基地。敌人基地会出来敌人,为了防止敌人攻进我方基地,我们可以选择造塔。每个节点只能造一个塔,节点i有ki种塔供选择,价值和攻击力为price_i, power_i,攻击力power_i是让敌人经过这个节点时让敌人的HP减少power_i点。因此从敌人基地到我方任意一个基地的路径,这条路径上所有塔的攻击力之和,就是这个基地的抵抗力。 敌人攻击路径不确定,为了保护我方所有基地,需要确定所有基地中抵抗力最低的一个。我方只有数量为m的钱,问在使用最优方案时,我方能够抵挡敌人的最大HP是多少?相当于让所有基地中抵抗力最低的一个的抵御力尽量大,最大是多少?

分析:这题参考了其他人的做法,树形DP+分组背包,为了能够防守,需要从敌方基地开始攻击,这样就可以从根节点1开始状态转移。要保住我方每个基地,每个结点就要先找出容量为j时儿子结点攻击掉的最小hp,可通过把儿子结点dp[v][j](dp[i][j]表示i结点费用j时打掉的最大hp)当作一个物品,每个v对应一组背包,计算max(t,min(dp[son][j-k],dp[v][k]))获得一个组合,容量为j,里面的最小值最大,赋值给dp[i][j]。

       需算出每个点i,在给予j的钱,能修建出的出的最大的稳定防御力dp[i][j],再用最小背包解决即可;对于i来说要求出的是在钱为j的前提下,最大攻击力,对于孩子,是求最大的最小防御力,最小就是按照某种方式分配钱修防御系统时,最薄弱(最小)的防御孩子是多少;最大相当于全部的方式中最大的最薄弱防御值,这样可以得到不考虑i时的dp[i][j]值,然后再在此基础上讨论i选择哪种拦截系统,就是一个简单背包dp了,该题用了两次 dp将问题简化。

#include<iostream>
#include<vector>
using namespace std;

#define N 1005
#define M 205
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

int attack[N][M];   //attack[i][j]表示节点i费用为j时的最大攻击力
int dp[N][M];      //dp[i][j]表示节点i费用为j时的能够攻击的最小攻击
int inf=0x7fffffff;
vector<int> map[N];    //树形地图
int n,m;

void initmap()            //初始化地图
{
	int i;

	for(i=0;i<=n;i++)
		map[i].clear();
}

void initdpattack()    //初始化每种炮台攻击及最小抵御攻击
{
	int i,j;

	for(i=0;i<=n;i++)
		for(j=0;j<=m;j++)
		{
			attack[i][j]=0;
			dp[i][j]=inf;
		}
}

void dfs(int u,int fa)  //u代表当前节点,fa代表父节点
{
	int size,i,k,j,v,minn;

	size=map[u].size();
	if(u!=1 && size==1)    //叶子节点
	{
		for(i=m;i>=0;i--)
			dp[u][i]=attack[u][i];
		return ;
	}
	for(i=0;i<size;i++)    //对于每一个子节点
	{
		v=map[u][i];

		if(v==fa) continue; //排除父节点,避免回搜
		dfs(v,u);
		for(j=m;j>=0;j--)
		{
			minn=0;
			for(k=0;k<=j;k++) //找到孩子节点的最小值中的最大值
			{
				minn=max(minn,min(dp[u][j-k],dp[v][k]));  //每次分k的费用给孩子节点
			}
			dp[u][j]=minn;        //这里没有选择根节点
		}
	}
	for(j=m;j>=0;j--)       //根节点选择了一组数据
		for(k=0;k<=j;k++)
			dp[u][j]=max(dp[u][j],dp[u][j-k]+attack[u][k]);
}

int main()
{
	int T,i,j,u,v,num,price,power;

	ios::sync_with_stdio(false);
	cin>>T;
	while(T--)
	{
		cin>>n;
		initmap();
		for(i=1;i<n;i++)
		{
			cin>>u>>v;
			map[u].push_back(v);
			map[v].push_back(u);
		}
		cin>>m;
		initdpattack();
		for(i=1;i<=n;i++)
		{
			cin>>num;
			for(j=1;j<=num;j++)
			{
				cin>>price>>power;
				attack[i][price]=max(attack[i][price],power);
			}
		}

		dfs(1,0); //从根节点开始dfs,开始没有父节点
		cout<<dp[1][m]<<endl;   //输出节点1(根节点)花费为m时能够攻击的最小攻击,也就是能够打掉敌人的HP
	}
    return 0;
}


HDU ACM 4044 GeoDefense ->树形DP+分组背包

标签:c   c++   acm   算法   编程   

原文地址:http://blog.csdn.net/a809146548/article/details/45695207

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!