1. 程式人生 > >樹形dp-訪問美術館

樹形dp-訪問美術館

主要問題: 樹如何編號(重點:如何體現父子關係)

樹的編號方式:

1)讀入給了編號並給予父子關係 (父子關係已給出) 處理:同存圖

2)將陣列轉化為一個樹 父子關係體現在其編號上(編號的關係->父子關係)典型:線段樹,堆(lson:2*x rson: 2*x+1)

void dfs(int x)
{
	cin>>a[x].x>>a[x].w;
	a[x].x*=2;
	if(a[x].w==0)
	{
		dfs(x*2);dfs(x*2+1);
	}
}

3)直接搞dfs序,一邊深搜一邊編號

void find()
{
	cnt++;int x=cnt;
	int a,b;cin>>a>>b;
	if(b==0)
	{
		int l=cnt+1,r;find();
		r=cnt+1;find();
		v[x].push_back(l);v[x].push_back(r);
	}
}

Then是完整程式碼

方法1:dfs序

由於輸入的訪問次序與dfs序相同,所以直接做一遍dfs找出lson,rson即可,無需額外儲存父子關係

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;
const int maxn=1005;
vector<int> v[maxn];
int f[maxn][maxn];
int cnt=0;
int n;
void find()
{
	cnt++;int x=cnt;
	int w,val;cin>>w>>val;
	w*=2;
	if(val==0)
	{
		int l=cnt+1,r;find();
		r=cnt+1;find();
		for(int tim=w;tim<=n;tim++)
		{
			for(int p=0;p<=tim-w;p++)
			{
				int temp=f[l][p]+f[r][tim-w-p];
				f[x][tim]=max(f[x][tim],temp);	
			}
		}
	}
	else
	{
		for(int tim=w;tim<=n;tim++)
		{
			f[cnt][tim]=min(val,(tim-w)/5); 
		} 
	}
}
int main()
{
	cin>>n;n--; 
	find();
	cout<<f[1][n]<<endl;
	return 0;
}

方法2:採用線段樹的儲存方法(lson=2*x,rson=2*x+1)

此方法可能存在空結點,沒有完全利用。

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

const int maxn=1005;
struct node
{
	int x;int w;
}a[maxn];
int f[maxn][maxn];
int cnt;node k;
void dfs(int x)
{
	cin>>a[x].x>>a[x].w;
	a[x].x*=2;
	if(a[x].w==0)
	{
		dfs(x*2);dfs(x*2+1);
	}
}
int find(int x,int cost)
{
	if(cost==0||f[x][cost]) return f[x][cost];
	if(a[x].w) return f[x][cost]=min(a[x].w,(cost-a[x].x)/5);
	for(int p=0;p<=cost-a[x].x;p++)
	{
		int temp=find(x*2,p)+find(x*2+1,cost-p-a[x].x);
		f[x][cost]=max(f[x][cost],temp);
	}
	return f[x][cost];
}
int main()
{
	int t;scanf("%d",&t);t-=1;
	dfs(1);
	cnt=0;
	cout<<find(1,t)<<endl;
	return 0;
 }