动态规划课程树型dp例题讲解及代码(持续更新中……)
小G有一个大树
解题思路
AC代码
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f; const int N=1e6+10; int sum=inf,node,n,w[N]; vector<int> tree[N]; void dfs(int x,int fa) { int maxx=0; w[x]=1; for(int i=0;i<tree[x].size();i++) { int tx=tree[x][i]; if(tx==fa) continue; dfs(tx,x); w[x]+=w[tx]; maxx=max(maxx,w[tx]); } maxx=max(maxx,n-w[x]); if(maxx<sum) { sum=maxx; node=x; } else if(maxx==sum) { node=min(x,node); } } int main(){ while(cin>>n) { sum=inf;node=0; memset(w,0,sizeof w); for(int i=1;i<=n;i++) tree[i].clear(); for(int i=1;i<n;i++) { int u,v; cin>>u>>v; tree[u].push_back(v); tree[v].push_back(u); } dfs(1,0); cout<<node<<' '<<sum<<endl; } }
Rinne Loves Edges
解题思路
坑人的地方就是最后的数据说明:M=N-1,就是棵树!
定义好dp的含义才是最重要的。
dp[i]表示以i为根节点的子树,不存在1度结点与之相连通,所需要的最小花费。
转移方程:dp[x] = ∑(min(dp[tx], cost(x,tx))) 其中tx为x的子节点。
AC代码
#include<bits/stdc++.h> #define pb push_back using namespace std; const int inf=0x3f3f3f3f; const int N=1e5+100; struct node{ int to,cost; }; vector<node> g[N]; int dp[N],n,m,s; void dfs(int x,int fa) { int sum=0; dp[x]=0; for(int i=0;i<g[x].size();i++) { if(fa==g[x][i].to) continue; dfs(g[x][i].to,x); if(dp[g[x][i].to]==0) dp[g[x][i].to]=inf;//注意! dp[x]+=min(dp[g[x][i].to],g[x][i].cost); } } int main(){ cin>>n>>m>>s; for(int i=1;i<=m;i++) { int u,v,w;cin>>u>>v>>w; node tmp;tmp.to=v;tmp.cost=w; //用结构体的思考过程(比较好想):如何存花费,用二维数组明显开不下,那就用二维vector,虽然能存下了,但是dfs的时候对应儿子结点,最后为了将结点与花费联系起来,就放在了结构体vector里了 g[u].pb(tmp); tmp.to=u; g[v].pb(tmp); } dfs(s,0); cout<<dp[s]<<endl; }
dp 文章被收录于专栏
菜