日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[洛谷P3262]战争调度

發布時間:2023/12/8 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [洛谷P3262]战争调度 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目

傳送門 to luogu

思路

編程要從娃娃抓起,dp\tt{dp}dp 要從葉節點搞起。

畢竟 每個葉節點之間是相互獨立的,并且貢獻只與其祖先(“祖先”不包括自己,下同)有關

一般樹形 dp\tt{dp}dp 都是存整個子樹的情況。此題相同。f(x)f(x)f(x)xxx 的子樹中所有葉子節點的貢獻和最大值。

假設某個葉節點的所有祖先的狀態都確定,那么枚舉一下這個葉節點的狀態,就可以得到這個點的最優值。

那么倒數第二層,也假設它的所有祖先節點狀態都確定,借用葉子節點的枚舉思想:這個點選擇 000 ,那么其兩個子樹應該分別取最大。而且恰好是前面已經處理了的祖先節點狀態全部確定的最大值!

至于去打仗的平民數量……加入 DP\tt{DP}DP 式考慮范圍即可!

f(s,x,y)=max?u=0yf(s′,x1,u)+f(s′,x2,y?u)f(s,x,y)=\max_{u=0}^{y}f(s',x_1,u)+f(s',x_2,y-u)f(s,x,y)=u=0maxy?f(s,x1?,u)+f(s,x2?,y?u)

sss 是祖先節點的狀態(狀壓 一下嘛!),xxx 是當前節點,x1,x2x_{1},x_2x1?,x2? 指兩個兒子。uuu 是去打仗的平民人數。注意兩個 fff 函數中的 s′s's 是一樣的哦。

感覺很費……時間復雜度是多少呢?一層一層考慮:(將根節點記為第111層)

kkk 層共有 2k?12^{k-1}2k?1 個點,每個點的處理時間為 2k2^{k}2ks′s's 的種類數)×2n?k?1\times 2^{n-k-1}×2n?k?1(左子樹中枚舉打仗的平民個數)×2n?k?1\times2^{n-k-1}×2n?k?1(右子樹中枚舉打仗的平民個數)=22n?k?2=2^{2n-k-2}=22n?k?2,相乘可得:第 kkk 層的總時間復雜度為 22n?22^{2n-2}22n?2 。驚喜!與 kkk 無關!

一共 nnn 層,總時間復雜度 O(n4n)\mathcal O(n4^n)O(n4n) ,常數小。

代碼實現時無需記憶化,因為沒有重復計算。但是父節點需要用子節點的值,所以要存一下,但 不用存 sss 。因為父節點知道 s′s's 是啥!

代碼

#include <cstdio> #include <iostream> #include <vector> using namespace std;const int MaxN = 1<<10; int war[MaxN][10], farmer[MaxN][10], n;int dp[MaxN][MaxN], size; void dfs(int s,int x){for(int i=0; i<=size; ++i)dp[x][i] = 0; // 不同的s都要跑,記得initif(size == 1){ // 葉子節點for(int i=0; i<n-1; ++i)if(s>>i&1)dp[x][1] += war[x][i];elsedp[x][0] += farmer[x][i];return ;}size >>= 1;for(int zxy=0; zxy<2; ++zxy){dfs(s<<1|zxy,x<<1);dfs(s<<1|zxy,x<<1|1);for(int i=0; i<=size; ++i)for(int j=0; j<=size; ++j)dp[x][i+j] = max(dp[x][i+j],dp[x<<1][i]+dp[x<<1|1][j]);}size <<= 1; // restore }int main(){scanf("%d",&n); int m; scanf("%d",&m);for(int i=(1<<n>>1); i<(1<<n); ++i)for(int j=0; j<n-1; ++j)scanf("%d",&war[i][j]);for(int i=(1<<n>>1); i<(1<<n); ++i)for(int j=0; j<n-1; ++j)scanf("%d",&farmer[i][j]);size = (1<<n>>1), dfs(0,1);int ans = 0;for(int i=0; i<=m; ++i)ans = max(ans,dp[1][i]);printf("%d",ans);return 0; }

總結

以上是生活随笔為你收集整理的[洛谷P3262]战争调度的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。