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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

树形dp初步

發布時間:2023/12/18 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 树形dp初步 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

其實很早之前就學過樹形dp,今天總接一下。樹形dp就是一個在樹上跑的dp(滑稽)

先是一道板子題:樹上最大獨立集

直接上代碼了。

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; struct node {int x,y,next; }; node a[110005]; int len,last[110005]; void add(int x,int y) {a[++len].x = x;a[len].y = y;a[len].next = last[x];last[x] = len; } int fa[11000],son[11000]; int f[11000][2]; int v[110000]; /* f[i][1]代表請i的最大值 f[i][0]代表不請i的最大值 */ template <class T> void read(T &x) {char c;int op = 0;while(c = getchar(),c > '9' || c < '0')if(c == '-') op = 1;x = c - '0';while(c = getchar(),c >= '0' && c <= '9')x = x * 10 + c - '0';if(op == 1)x = -x; } void treedp(int x) {f[x][1] = v[x];for(int k = last[x];k;k = a[k].next) //相當于dfs treedp(a[k].y);for(int k = last[x];k;k = a[k].next){int y = a[k].y;f[x][1] += f[y][0]; //dp轉移式① }f[x][0] = 0;for(int k = last[x];k;k = a[k].next){int y = a[k].y;f[x][0] += max(f[y][0],f[y][1]);//dp轉移式② } } int main() {int n;read(n);memset(f,-1,sizeof(f));memset(fa,0,sizeof(fa));for(int i = 1;i <= n;i++)read(v[i]);int xx,yy;len = 0;memset(last,0,sizeof(last));while(scanf("%d%d",&xx,&yy) != EOF){if(xx == 0 && yy == 0){break;}add(yy,xx);fa[xx] = yy; //找根節點 }int root = 0;for(int i = 1;i <= n;i++)if(fa[i] == 0){root = i;break;}treedp(root);printf("%d\n",max(f[root][0],f[root][1]));return 0; }

然后還有幾個稍微比這個難一點的題,比如:加分二叉樹

【問題描述】 設一個有n個節點的二叉樹的中序遍歷為(l,2,3,…,n),其中數字1,2,3,…,n為節點編號。 每個節點都有一個分數(均為正整數),記第i個節點的分數為di, 每棵子樹都有一個加分,任一棵子樹subtree的加分計算方法如下:subtree的左子樹的加分× subtree的右子樹的加分+subtree的根的分數若某個子樹為空,規定其加分為1,葉子的加分就是葉節點本身的分數。不考慮它的空子樹。試求一棵符合中序遍歷為(1,2,3,…,n)且加分最高的二叉樹tree。要求輸出;(1)tree的最高加分(2)tree的前序遍歷 【輸入格式】第1行:一個整數n(n<30),為節點個數。第2行:n個用空格隔開的整數,為每個節點的分數(分數<100)。 【輸出格式】第1行:一個整數,為最高加分(結果不會超過2,0 0000 0000)。第2行:n個用空格隔開的整數,為該樹的前序遍歷。 【樣例輸入】 5 5 7 1 2 10 【樣例輸出】 145 3 1 2 4 5

這個題需要枚舉中間的斷點,然后進行dp。dp比之前簡單了,但是其他的要難一些。

#include<cstdio> #include<iostream> using namespace std; int root[50][50],d[50],f[50][50]; void pre_visit(int l,int r) {if(l <= r){cout<<root[l][r]<<" ";pre_visit(l,root[l][r] - 1);pre_visit(root[l][r] + 1, r);} } int main() {int m;cin>>m;for(int i = 0;i <= m;i++){for(int j = 0;j <= m;j++){f[i][j] = 1;}}for(int i = 1;i <= m;i++){cin>>d[i];root[i][i] = i;f[i][i] = d[i];}for(int k = 2;k <= m;k++){for(int l = 1;l <= m - k + 1;l++){int r = l + k - 1;for(int i = l;i <= r;i++){if(f[l][r] < f[l][i - 1] * f[i + 1][r] + d[i]){root[l][r] = i;f[l][r] = f[l][i - 1] * f[i + 1][r] + d[i];}}}}cout<<f[1][m]<<endl;cout<<root[1][m]<<" ";pre_visit(1,root[1][m] - 1);pre_visit(root[1][m] + 1,m); }

還有一個皇宮看守,和最大獨立點集很像

【問題描述】 太平王世子事件后,陸小鳳成了皇上特聘的御前一品侍衛。 皇宮以午門為起點,直到后宮嬪妃們的寢宮,呈一棵樹的形狀;有邊直接相連的宮殿可以互相望見。大內保衛森嚴,三步一崗,五步一哨,每個宮殿都要有人全天候看守,在不同的宮殿安排看守所需的費用不同。 可是陸小鳳手上的經費不足,無論如何也沒法在每個宮殿都安置留守侍衛。編程任務:幫助陸小鳳布置侍衛,在看守全部宮殿的前提下,使得花費的經費最少。 【輸入格式】 輸入文件中數據表示一棵樹,描述如下: 第1行 n,表示樹中結點的數目。 第2行至第n+1行,每行描述每個宮殿結點信息,依次為:該宮殿結點標號i(0<I<=N),在該宮殿安置侍衛所需的經費K,該點的兒子數M,接下來M個數,分別是這個節點的M個兒子的標號R1,R2,...,RM。對于一個n(0 < n<=1500)個結點的樹,結點標號在1到n之間,且標號不重復。 【輸出格式】 輸出文件僅包含一個數,為所求的最少的經費。 輸入樣例: 6 1 30 3 2 3 4 2 16 2 5 6 3 5 0 4 4 0 5 11 0 6 5 0 輸出樣例: 25

這個題很好想。

#include<iostream> #include<cstring> using namespace std; typedef long long ll; struct node {ll x,y,next; }; node a[110000]; ll v[100000],f[100000][5]; ll last[200000],len = 0; bool bk[50000]; /* i節點安全代表i節點和子樹安全 不安全代表i節點不安全,但是子樹安全 f[i][0]表示x點不放人,但是安全 f[i][1]表示x點不放人,不安全 f[i][2]表示x點放人,所以安全 f[i][3]表示x點放人,但是不安全,顯然不成立 */ void treedp(int x) {f[x][2] = v[x];f[x][1] = 0;f[x][0] = 0;ll minn = 2147364847;bool bkk = false;for(int k = last[x];k;k = a[k].next){ll y = a[k].y;if(bk[y] == false){bk[y] = true;treedp(y);minn = min(f[y][2] - f[y][0],minn);f[x][0] += min(f[y][0],f[y][2]);if(f[y][2] <= f[y][0]){bkk = true;}//一定選f[i][2] f[x][1] += f[y][0];f[x][2] += min(f[y][2],min(f[y][1],f[y][0]));}}if(bkk == false){f[x][0] += minn;} } void add(int x,int y) {a[++len].x = x;a[len].y = y;a[len].next = last[x];last[x] = len; } int main() {ll n;cin>>n;memset(f,0,sizeof(f));for(int i = 1;i <= n;i++){ll x,m,k;cin>>x>>k>>m;v[x] = k;for(int j = 1;j <= m;j++){ll y;cin>>y;add(x,y);add(y,x);}}ll root = 1;memset(bk,false,sizeof(bk));bk[root] = true;treedp(root);cout<<min(f[root][0],f[root][2]);return 0; }

?

轉載于:https://www.cnblogs.com/DukeLv/p/9478497.html

總結

以上是生活随笔為你收集整理的树形dp初步的全部內容,希望文章能夠幫你解決所遇到的問題。

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