天天看點

POJ2486&&POJ3659 ——樹形動态規劃

兩道題都折騰了很長時間,總算過了。樹形動規,主要在于動規順序,其次才是狀态的設計。

POJ2486:

先用左兒子右兄弟表示法進行多叉轉二叉。

f[i][j]表示從i點出發走了j步、最後不一定要回到i點能吃到的最多蘋果數

g[i][j]表示從i點出發走了j步、最後回到i點所能吃到的最多蘋果數

動規方程比較複雜:

f[i][j]=Max{f[left[i],k],g[right[i],j-3-k]+a[i]}(0<=k<=j-3)

f[i][j]=Max{f[i,j],g[left[i],k]+f[right[i],j-4-k]+a[i]}(0<=k<=j-4)

g[i][j]=Max{g[i,k]+g[i,j-4-k]+a[i]}(0<=k<=j-4)

代碼如下:

Program POJ2486;//By_Thispoet
Const
	maxn=105;
Var
	i,j,k,n,m,p,q,o,tmp					:Longint;
	f,g									:Array[0..maxn,0..maxn*2]of Longint;//f not back,g back
	a,left,right,re,father				:Array[0..maxn]of Longint;
	seq,pre,other,last					:Array[0..maxn*2]of Longint;
	h,t									:Longint;

Function Max(i,j:Longint):Longint;
begin
	if i>j then exit(i);exit(j);
end;


Procedure Bfs();
begin
	h:=0;t:=1;seq[1]:=1;
	while h<t do
		begin
			inc(h);
			i:=seq[h];
			j:=last[i];
			while j<>0 do
				begin
					k:=other[j];
					if k<>father[i] then
						begin
							father[k]:=i;
							if re[i]=0 then
								begin
									left[i]:=k;
									re[i]:=k;
								end else
								begin
									right[re[i]]:=k;
									re[i]:=k;
								end;
							inc(t);seq[t]:=k;
						end;
					j:=pre[j];
				end;
		end;
end;


BEGIN

	readln(n,o);
	while not eof do
		begin
			for i:=1 to n do read(a[i]);
			fillchar(father,sizeof(father),0);
			fillchar(f,sizeof(f),0);
			fillchar(g,sizeof(g),0);
			fillchar(re,sizeof(re),0);
			fillchar(left,sizeof(left),0);
			fillchar(right,sizeof(right),0);
			fillchar(last,sizeof(last),0);
			k:=0;
			for i:=1 to n-1 do
				begin
					readln(p,q);
					inc(k);pre[k]:=last[p];last[p]:=k;other[k]:=q;
					inc(k);pre[k]:=last[q];last[q]:=k;other[k]:=p;
				end;

			Bfs();

			while t>0 do
				begin
					i:=seq[t];
					for j:=0 to o do
						begin
							f[i,j]:=Max(f[right[i],j],a[i]);
							g[i,j]:=Max(g[right[i],j],a[i]);
							if j>=1 then
								begin
									f[i,j]:=Max(f[i,j],f[left[i],j-1]+a[i]);
								end;
							if j>=2 then
								begin
									f[i,j]:=Max(f[i,j],f[right[i],j-2]+a[i]);
									g[i,j]:=Max(g[i,j],g[left[i],j-2]+a[i]);
									g[i,j]:=Max(g[i,j],g[right[i],j-2]+a[i]);
								end;
							for k:=0 to j-3 do
								begin
									f[i,j]:=Max(f[i,j],f[left[i],k]+g[right[i],j-3-k]+a[i]);
								end;
							for k:=0 to j-4 do
								begin
									g[i,j]:=Max(g[i,j],g[left[i],k]+g[right[i],j-4-k]+a[i]);
									f[i,j]:=Max(f[i,j],g[left[i],k]+f[right[i],j-4-k]+a[i]);
								end;
						end;
					dec(t);
				end;

			writeln(f[1,o]);

			readln(n,o);
		end;

END.
           

POJ3659:

f[i][0]表示i這個點依賴于子節點的電話亭,且以i為根的子樹全部被覆寫時所用的最少電話亭數

f[i][1]表示i這個點建電話亭且滿足上述條件的最少電話亭數

f[i][2]表示i這個點依賴于父節點的電話亭求滿足上述條件的最少電話亭數

狀态轉移方程很簡單,直接看代碼就能懂的:

Program Tower;//By_Thispoet
Const
	maxn=10005;
Var
	i,j,k,n,h,t,p,q					:Integer;
	f								:Array[1..maxn,0..2]of Integer;
	pre,other,last,seq				:Array[1..maxn*2]of Integer;
	father,leaf						:Array[1..maxn]of Integer;

Function Min(i,j:Longint):Longint;
begin
	if i<j then exit(i);exit(j);
end;


Procedure Bfs();
begin
	h:=0;t:=1;seq[t]:=1;
	while h<t do
		begin
			inc(h);
			i:=seq[h];
			j:=last[i];
			while j<>0 do
				begin
					k:=other[j];
					if k<>father[i] then
						begin
							father[k]:=i;
							leaf[i]:=1;
							inc(t);seq[t]:=k;
						end;
					j:=pre[j];
				end;
		end;
end;
	
	
Procedure Dp();
var flag:Boolean;
	mini:Longint;
begin
	while t>0 do
		begin
			i:=seq[t];
			flag:=false;
			if leaf[i]=0 then
				begin
					f[i,0]:=maxint;
					f[i,1]:=1;
					f[i,2]:=0;
				end else
					begin
						j:=last[i];
						while j<>0 do
							begin
								k:=other[j];
								if k<>father[i] then 
									begin
										if f[k,1]<=f[k,0] then
											begin
												flag:=true;
												inc(f[i,0],f[k,1]);
											end else inc(f[i,0],f[k,0]);
										inc(f[i,1],Min(f[k,1],f[k,2]));
										inc(f[i,2],Min(f[k,1],f[k,0]));
									end;
								j:=pre[j];
							end;
						inc(f[i,1]);
						if not flag then inc(f[i,0]);
					end;
			dec(t);
		end;
end;


BEGIN

	readln(n);
	for i:=1 to n-1 do
		begin
			readln(p,q);
			inc(k);pre[k]:=last[p];last[p]:=k;other[k]:=q;
			inc(k);pre[k]:=last[q];last[q]:=k;other[k]:=p;
		end;

	Bfs();
	fillchar(f,sizeof(f),0);

	Dp();
	writeln(Min(f[1,0],f[1,1]));

END.
           

轉載于:https://www.cnblogs.com/Thispoet/archive/2011/09/27/2192876.html