演算法:樹型dp
與戰略遊戲1不同的是,戰略遊戲1是看邊,也就是只能由父親結點看子結點,而本題是某個結點可以由父親看,可以放士兵,也可以讓兒子看,因此有三種狀態。有三種轉移方式。
f[t,0]表示t被父親結點的士兵守衛。因此f[t,0]=f[t,0]+σmin(f[tot[t,i],1],f[tot[t,i],2])。tot[t,i]表示t的第i個兒子。dp方程可以解釋為:若當前結點被父親結點守衛,則它的子節點要麼放守衛,要麼被子結點守衛,兩者取乙個最小值。
f[t,1]表示t放士兵守衛。因此f[t,1]=f[t,1]+1+σmin(f[tot[t,i],1],f[tot[t,i],2],f[tot[t,i],3])。若這個點放士兵,子結點可以被父親守衛,可以放士兵,也可以被子子結點守衛。
f[t,2]表示t被子結點守衛。因此f[t,2]=f[t,2]+min(f[tot[t,i],1])+σmin(f[tot[t,i],1],f[tot[t,i],2])。若這個點被子結點守衛,子結點必須有乙個點放士兵,通過打擂台找到這個士兵。同時其它點可以放士兵,也可以被子結點守衛,在計算時就不能再把放士兵的那個點算上。
program toj1147;
const
maxn1=1500;
var f:array [0..maxn1,0..2] of longint;
tot:array [0..maxn1,0..maxn1] of longint;
fa:array [0..maxn1] of longint;
n,root:longint;
procedure init;
var i,j,x,t,y:longint;
begin
fillchar(f,sizeof(f),0);
fillchar(fa,sizeof(fa),255);
readln(n);
for i:=1 to n do
begin
read(x,t);
tot[x,0]:=t;
for j:=1 to t do
begin
read(y);
tot[x,j]:=y;
fa[y]:=x;
end;
readln;
end;
for i:=0 to n-1 do
begin
if fa[i]=-1 then
begin
root:=i;
break;
end;
end;
end;
function min(x,y:longint):longint;
begin
if xp then inc(sum,min(f[tot[t,i],1],f[tot[t,i],2]));
f[t,2]:=sum;
end;
begin
assign(input,'toj1174.in'); reset(input);
assign(output,'toj1174.out'); rewrite(output);
init;
tree_dp(root);
writeln(min(f[root,1],f[root,2]));
close(input); close(output);
end.
TYVJ3097 3121 3369 戰略遊戲
給一棵n個節點的樹,在點上放置士兵,每個士兵能監視周圍的所有邊,詢問最少放置的士兵數dp i,0 表示在 i點不放 士兵合法 的最小放 置數dp i,1 表示在 i點放士 兵合法的 最小放置 數 dp i,0 d p so n i 1 dp i 1 dp son i 1 d p so n i 0 m...
P2016 戰略遊戲
樹形dp f u 0 表示 uf u 0 表示u f u 0 表示u 號節點不放士兵,以x為根的子樹需要的最少士兵數。f u 1 表示 uf u 1 表示u f u 1 表示u 號節點放士兵,以x為根的子樹需要的最少士兵數。由於我們定義的是將其完全覆蓋,則我們不需要考慮父親節點,為什麼?當我們已經回...
藍書 323 戰略遊戲
f i 2 以i為根的子樹,i節點不放置士兵滿足條件的最小放置士兵數量。樹形dp一下就行 比較奇怪的是 讀入scanf d d u,m 是對的 scanf d s u,s int m s 2 0 這樣就會超時。有懂得大佬解答下嗎。include using namespace std typedef...