標籤:blog 超過 using 並且 eof 數組 href hive for
Apple Tree POJ - 2486
題目大意:一棵點帶權有根樹,根節點為1。從根節點出發,走k步,求能收集的最大權值和。
樹形dp。複雜度可能是O(玄學),不會超過$O(nk^2)$。(反正這題不卡這個,考思想)參考
ans[i][j][0]表示i點以下共走j步,不回來,可能收集到最大的權值
ans[i][j][1]表示i點以下共走j步,回來,可能收集到最大的權值
比較複雜的是,每個節點(以下稱當前節點)從其子節點轉移的時候,需要用一個背包:
t[i][j][0]表示當前節點的前i個子節點共走j步,不回來
t[i][j][1]表示當前節點的前i個子節點共走j步,回來
對於t[i][j][0],要麼是當前節點的前i-1個子節點共走j步(包括去和回來前面的子節點所用步數),在之前就不回來;
要麼是前i-1個子節點共走j-p步(包括去和回來前面的子節點所用步數),當前節點走到第i個子節點用1步,第i個子節點向下走p-1步,不回來;
要麼是花一步走到第i個子節點,在第i個子節點往下走p-2步,再花一步走回當前節點,再在前i-1個子節點中走j-p步(包括去和回來前面的子節點所用步數)並且不回來。
因此t[i][j][0]=max(t[i-1][j][0],max{t[i-1][j-p][1]+ans[nowson][p-1][0]},max{t[i-1][j-p][0]+ans[nowson][p-2][1]})
對於t[i][j][1],要麼是前i-1個子節點共走j-p步(包括去和回來前面的子節點所用步數),走到第i個子節點花1步,第i個子節點向下走用p-2步並回來,從第i個子節點回來花一步;要麼是前i-1個子節點共走j步(包括去和回來前面的子節點所用步數),回來。
因此t[i][j][1]=max(t[i-1][j][1],max{t[i-1][j-p][1]+ans[nowson][p-2][1]})
當然實際求解的時候並不需要每個節點開一個t數組,只需要在ans數組上直接做就行了。就是先對t數組求解過程用滾動數組最佳化,那麼只需要兩維t[j][0/1]。這時只需要把ans[當前節點]的數組當做t去做就行了。另外,求解t數組的邊界要注意一下。另外,t數組再求解前就全部初始化成當前節點權值就行了。
最終答案很顯然:max(ans[1][k][0],ans[1][k][1])。
曾經錯誤:
naive的轉移方程:
t[i][j][0]=max(t[i-1][j][0],t[i-1][j-p][0],t[i-1][j-p][1]+ans[son][p][0])
t[i][j][1]=max(t[i-1][j][1],t[i-1][j-p][1]+ans[son][p][1])
事實上,這道題轉移t[i][j][0]的第3種(標紅的)情況很容易遺漏。另外,很容易忽略走去與走回子節點花費的1或2步。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 struct Edge 6 { 7 int to,next; 8 }edge[210]; 9 int ne,ans[110][210][2],f1[110];10 int a[110];11 int n,k;12 bool vis[110];13 void dfs(int u)14 {15 int j,kk=f1[u],p,v;16 vis[u]=true;17 for(j=0;j<=k;j++)18 ans[u][j][0]=ans[u][j][1]=a[u];19 while(kk!=0)20 {21 v=edge[kk].to;22 if(!vis[v])23 {24 dfs(v);25 for(j=k;j>=0;j--)26 {27 for(p=1;p<=j;p++)28 ans[u][j][0]=max(ans[u][j][0],max(ans[u][j-p][0]+ans[v][p-2][1],ans[u][j-p][1]+ans[v][p-1][0]));29 for(p=2;p<=j;p++)30 ans[u][j][1]=max(ans[u][j][1],ans[u][j-p][1]+ans[v][p-2][1]);31 }32 }33 kk=edge[kk].next;34 }35 }36 int main()37 {38 int i,ta,tb;39 while(scanf("%d%d",&n,&k)==2)40 {41 ne=0;42 memset(ans,0,sizeof(ans));43 memset(vis,0,sizeof(vis));44 memset(f1,0,sizeof(f1));45 for(i=1;i<=n;i++)46 scanf("%d",&a[i]);47 for(i=1;i<n;i++)48 {49 scanf("%d%d",&ta,&tb);50 edge[++ne].to=tb;51 edge[ne].next=f1[ta];52 f1[ta]=ne;53 edge[++ne].to=ta;54 edge[ne].next=f1[tb];55 f1[tb]=ne;56 }57 dfs(1);58 printf("%d\n",max(ans[1][k][0],ans[1][k][1]));59 }60 return 0;61 }
Apple Tree POJ - 2486