1. 程式人生 > >【動態規劃】搭建雙塔

【動態規劃】搭建雙塔

描述 Description
  2001年9月11日,一場突發的災難將紐約世界貿易中心大廈夷為平地,Mr. F曾親眼目睹了這次災難。為了紀念“9?11”事件,Mr. F決定自己用水晶來搭建一座雙塔。
  Mr. F有N塊水晶,每塊水晶有一個高度,他想用這N塊水晶搭建兩座有同樣高度的塔,使他們成為一座雙塔,Mr. F可以從這N塊水晶中任取M(1≤M≤N)塊來搭建。但是他不知道能否使兩座塔有同樣的高度,也不知道如果能搭建成一座雙塔,這座雙塔的最大高度是多少。所以他來請你幫忙。
  給定水晶的數量N(1≤N≤100)和每塊水晶的高度Hi(N塊水晶高度的總和不超過2000),你的任務是判斷Mr. F能否用這些水晶搭建成一座雙塔(兩座塔有同樣的高度),如果能,則輸出所能搭建的雙塔的最大高度,否則輸出“Impossible”。
輸入格式 Input Format
  輸入的第一行為一個數N,表示水晶的數量。第二行為N個數,第i個數表示第i個水晶的高度。
輸出格式 Output Format
  輸出僅包含一行,如果能搭成一座雙塔,則輸出雙塔的最大高度,否則輸出一個字串“Impossible”。
樣例輸入 Sample Input
樣例輸出 Sample Output

來源 Source

某校NOIP模擬題

揹包變形。傳統揹包加一維狀態。

f[j1,j2]表示對於前i個水晶,能不能構成高度分別為j1,j2的塔

f[j1,j2]=f[j1-v[i],j2] or  f[j1,j2-v[i]] or(f[j1,j2])

最後從大到小列舉i,若f[i,i]=true 則輸出i 結束程式

最後輸出 ‘Impossible'

注意i的下界不是0而是1

注意輸出 'impossible'

var i,j1,j2,n,max,s:longint;
    v:array[1..100]of longint;
    f:array[-1000..1000,-1000..1000]of boolean;
begin
    fillchar(f,sizeof(f),false);
    readln(n);
    for i:=1 to n do
    read(v[i]);s:=0;
    for i:=1 to n do s:=s+v[i];
    max:=s div 2;
    f[0,0]:=true;
    for i:=1 to n do
    for j1:=max downto 0 do
    for j2:=max downto 0 do
    f[j1,j2]:=(f[j1-v[i],j2])or(f[j1,j2-v[i]])or(f[j1,j2]);
    for i:=max downto 1 do
    if f[i,i] then
    begin
        writeln(i);
        exit;
    end;
    writeln('Impossible');
    readln;readln;
end.