树形dp小胖守皇宫(vijosP1144)
生活随笔
收集整理的這篇文章主要介紹了
树形dp小胖守皇宫(vijosP1144)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:https://vijos.org/p/1144
題解:這道題的動歸稍稍有一點的復雜,因為一個節點有可能被它的子節點觀察,也有可能被父節點觀察;
所以我們這樣表示:
? f[i][0](表示當前i節點放了一個看守,即他自己和所有子節點已經被控制好)
? f[i][1](表示當前i節點不放看守,但是他自己和所有子節點已經被控制好)
? f[i][2](表示當前解點不放看守,子節點已被控制好但他自己沒被控制)
? f[i][0]=sum(min(f[son][0],f[son][1],f[son][2]));(如果當前節點放的話,那上一步不管怎么樣都可以)
? f[i][1]=sum(min(f[son][0],f[son][1]));(需要子節點已經被控制好,但需要注意,如果每個兒子選的都是f[son][j][1],我們需要挑出代價最小的點,改成f[son][j][0],因為我們需要當前結點被控制);
? f[i][2]=sum(f[son][1]);
大概就是這么幾種情況,具體程序注釋里講;
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long LL; LL f[5000][5],cost[5000]; struct ding{int to,next; }edge[10000]; int head[10000],n,m,root,cnt; bool vis[5000]; void add(int u,int v){edge[++cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;} void dfs(int x) {bool fg=false;LL minx=2100000000;f[x][0]=cost[x];//先加上在這個點放守衛的代價for (int i=head[x];i;i=edge[i].next){int y=edge[i].to;dfs(y);f[x][0]+=min(min(f[y][1],f[y][2]),f[y][0]);minx=min(minx,f[y][0]-f[y][1]);//為了特判if (f[y][0]>f[y][1]) f[x][1]+=f[y][1];else {f[x][1]+=f[y][0];fg=true;//如果有任何一次取了f[i][0],就說明不需要特判 }f[x][2]+=f[y][1];}if (!fg) f[x][1]+=minx; //特殊情況 } int main() {int now,x;LL k; scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d%lld%d",&now,&k,&m);cost[now]=k;for (int j=1;j<=m;j++){scanf("%d",&x);add(now,x);vis[x]=true;}}for (int i=1;i<=n;i++) if (!vis[i]) root=i; //先找到根 dfs(root);printf("%lld\n",min(f[root][1],f[root][0]));return 0; }?
? ?
轉載于:https://www.cnblogs.com/2014nhc/p/6625427.html
總結
以上是生活随笔為你收集整理的树形dp小胖守皇宫(vijosP1144)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MUMU安卓模拟器怎么设置按键?
- 下一篇: 网易MuMu安卓模拟器启动卡在99% 解