1. 程式人生 > >gfoj 樹形dp “訪問”術館

gfoj 樹形dp “訪問”術館

經過數月的精心準備,Peer Brelstet,一個出了名的盜畫者,準備開始他的下一個行動。藝術館的結構,每條走廊要麼分叉為兩條走廊,要麼通向一個展覽室。Peer知道每個展室裡藏畫的數量,並且他精確測量了通過每條走廊的時間。由於經驗老到,他拿下一幅畫需要5秒的時間。你的任務是編一個程式,計算在警察趕來之前,他最多能偷到多少幅畫。

第1行是警察趕到的時間,以s為單位。第2行描述了藝術館的結構,是一串非負整數,成對地出現:每一對的第一個數是走過一條走廊的時間,第2個數是它末端的藏畫數量;如果第2個數是0,那麼說明這條走廊分叉為兩條另外的走廊。資料按照深度優先的次序給出,請看樣例。

一個展室最多有20幅畫。通過每個走廊的時間不超過20s。藝術館最多有100個展室。警察趕到的時間在10min以內。其中30%的資料展室最多有18間

看似複雜,實則樹形dp

前面處理好就可以了

輸入真滴噁心。。。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>

using namespace std;

struct node
{
	int x,y;
};
struct node1
{
	int x,len;
};

int t;
stack <node> s;
vector<node1> M[1000+5];
int f[1000+5][600+5],a[1000+5];

void dfs(int x)
{
	int i,j,k;
	node1 n1;
	
	if (M[x].size()==0)
		for (i=0;i<=a[x];i++)
			f[x][i*5]=i;
	for (i=0;i<M[x].size();i++)
	{
		n1=M[x][i];
		dfs(n1.x);
		for (j=t;j>=0;j--)
			for (k=0;k<=j-2*n1.len;k++)
				f[x][j]=max(f[x][j],f[x][j-2*n1.len-k]+f[n1.x][k]);
	}
}

int main()
{
	int i,x,y,i1,fa,ans;
	node n1,n2;
	node1 n11;
	
	freopen("a.txt","r",stdin);
	scanf("%d",&t);
	
	i1=0;	fa=0;
	while (1)
	{
		i1++;
		scanf("%d%d",&x,&a[i1]);
		n11.x=i1;	n11.len=x;
		M[fa].push_back(n11);
		if (a[i1]==0)
		{
			n1.x=i1;	n1.y=1;
			s.push(n1);
			fa=i1;
		}
		else
		{
			if (s.empty())
				break;
			n2=s.top();
			n2.y++;
			while (n2.y>2)
			{
				s.pop();
				if (s.empty())
					break;
				n2=s.top();
				n2.y++;
			}
			if (s.empty())
				break;
			s.pop();
			s.push(n2);
			fa=n2.x;
		}
	}
	memset(f,0,sizeof(f));
	dfs(0);
	
	ans=0;
	for (i=0;i<t;i++)
		ans=max(ans,f[0][i]);
	printf("%d\n",ans);
	
	return 0;
}