树形dp小结
地址:https://vjudge.net/contest/168217
最近做了大量的dp,同时完成了一套树形dp,刷tc的时候也做了好几道树形dp。 <del>感觉会做dp了</del>
先训练,有空再补上
HDU 1520 Anniversary party (入门中的入门)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 6005; int n; int e[maxn]; int dp[maxn][2]; vector<int> v[maxn]; void dfs(int x,int f) { dp[x][0] = e[x]; dp[x][1] = 0; for(int i = 0; i < v[x].size(); i++) { int c = v[x][i]; if(c == f) continue; dfs(c,x); dp[x][0] += dp[c][1]; dp[x][1] += max(dp[c][0],dp[c][1]); } } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); while(scanf("%d",&n) == 1) { for(int i = 1; i <= n; i++) {scanf("%d",e + i);v[i].clear();} int a,b; while(scanf("%d%d",&a,&b) && a) { v[a].push_back(b); v[b].push_back(a); } dfs(1,0); printf("%d\n",max(dp[1][0],dp[1][1])); } return 0; }
HDU 2196 Computer
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 100005; int n,m; int dp[maxn][2],id[maxn][2]; vector<int> v[maxn]; struct Edge { int to,len; Edge(int a = 0,int b = 0):to(a),len(b){} }edges[maxn<<1]; void upd(int& a,int& b,int c,int d,int e) { a = c + d; b = e; } void dfs1(int x,int f) { dp[x][0] = dp[x][1] = 0; id[x][0] = id[x][1] = 0; for(int i = 0; i < v[x].size(); i++) { int c = v[x][i]; int to = edges[c].to; if(to == f) continue; dfs1(to,x); if(dp[x][0] < dp[to][0] + edges[c].len) { dp[x][1] = dp[x][0]; id[x][1] = id[x][0]; upd(dp[x][0],id[x][0],dp[to][0],edges[c].len,to); } else if(dp[x][1] < dp[to][0] + edges[c].len) upd(dp[x][1],id[x][1],dp[to][0],edges[c].len,to); } } void dfs2(int x,int f,int l) { if(id[f][0] != x) { if(dp[x][0] < dp[f][0] + l) { dp[x][1] = dp[x][0]; id[x][1] = id[x][0]; upd(dp[x][0],id[x][0],dp[f][0],l,f); } else if(dp[x][1] < dp[f][0] + l) upd(dp[x][1],id[x][1],dp[f][0],l,f); } else { if(dp[x][0] < dp[f][1] + l) { dp[x][1] = dp[x][0]; id[x][1] = id[x][0]; upd(dp[x][0],id[x][0],dp[f][1],l,f); } else if(dp[x][1] < dp[f][1] + l) upd(dp[x][1],id[x][1],dp[f][1],l,f); } for(int i = 0; i < v[x].size(); i++) if(edges[v[x][i]].to != f) dfs2(edges[v[x][i]].to,x,edges[v[x][i]].len); } int main() { //freopen("b.in","r",stdin); //freopen("b.out","w",stdout); while(scanf("%d",&n) == 1) { m = 0; for(int i = 1; i <= n; i++) v[i].clear(); for(int i = 2; i <= n; i++) { int a,b; scanf("%d%d",&a,&b); edges[m] = Edge(a,b); v[i].push_back(m++); edges[m] = Edge(i,b); v[a].push_back(m++); } memset(dp,0,sizeof dp); dfs1(1,0); dp[0][0] = dp[0][1] = id[0][0] = id[0][1] = 0; dfs2(1,0,0); for(int i = 1; i <= n; i++) printf("%d\n",dp[i][0]); } return 0; }
CodeForces 219D Choosing Capital for Treeland
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 200005; int n; int d[maxn],cal[maxn]; struct Edge { int to,k; Edge(int a = 0,int b = 0):to(a),k(b){} }edges[maxn<<1]; vector<int> v[maxn]; void dfs1(int x,int f) { d[x] = cal[x] = 0; for(int i = 0; i < v[x].size(); i++) { int e = v[x][i]; int to = edges[e].to; if(to == f) continue; dfs1(to,x); d[x] += d[to] + edges[e].k ; cal[x] += cal[to] + 1; } } int ans; void dfs2(int x,int f,int k) { if(f) d[x] += d[f] - d[x] - k + (k ^ 1); if(d[x] < ans) ans = d[x]; for(int i = 0; i < v[x].size(); i++) { int e = v[x][i]; int to = edges[e].to; if(to != f) dfs2(to,x,edges[e].k); } } int main() { //freopen("c.in","r",stdin); //freopen("c.out","w",stdout); scanf("%d",&n); int m = 0; for(int i = 0; i < n - 1; i++) { int a,b; scanf("%d%d",&a,&b); edges[m] = Edge(b,0); v[a].push_back(m++); edges[m] = Edge(a,1); v[b].push_back(m++); } dfs1(1,0); //for(int i = 1; i <= n; i++) cout<<d[i]<<endl; //cout<<endl; ans = 1 << 30; dfs2(1,0,0); //for(int i = 1; i <= n; i++) cout<<d[i]<<endl; //cout<<endl; printf("%d\n",ans); for(int i = 1; i <= n; i++) if(d[i] == ans) printf("%d ",i); printf("\n"); return 0; }
HDU 3586 Information Disturbing
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 1005; int n,m; int dp[maxn],cal[maxn]; int to[maxn<<1],len[maxn<<1]; vector<int> v[maxn]; int cnt; void addEdge(int a,int b,int l) { to[++cnt] = b; len[cnt] = l; v[a].push_back(cnt); } void upd(int& a,int b) { if(a == -1) a = b; else a = max(a,b); } void dfs(int x,int fa) { if(x != 1 && v[x].size() == 1) { dp[x] = -1; return; } dp[x] = -1; cal[x] = 0; for(int i = 0; i < v[x].size(); i++) { int c = v[x][i]; if(to[c] == fa) continue; dfs(to[c],x); //if(x == 1) cout<<to[c]<<" "<<dp[to[c]]<<endl; if(dp[to[c]] == -1) { upd(dp[x],len[c]); cal[x] += len[c]; } else { upd(dp[x],min(dp[to[c]],len[c])); cal[x] += min(cal[to[c]],len[c]); } } } int main() { //freopen("d.in","r",stdin); //freopen("d.out","w",stdout); while(scanf("%d%d",&n,&m) == 2) { if(!n && !m) break; for(int i = 1; i <= n; i++) v[i].clear(); cnt = 0; for(int i = 0; i < n - 1; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); addEdge(a,b,c); addEdge(b,a,c); } dfs(1,0); printf("%d\n",cal[1] > m ? -1 : dp[1]); } return 0; }
POJ 3162 Walking Race
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 1000005; int n,m; int head[maxn],nxt[maxn<<1],to[maxn<<1],len[maxn<<1]; ll dp[maxn][2]; int id[maxn]; ll dist[maxn]; int cnt; void addEdge(int a,int b,int c) { to[++cnt] = b; len[cnt] = c; nxt[cnt] = head[a]; head[a] = cnt; } void dfs(int x,int fa) { dp[x][0] = dp[x][1] = 0; id[x] = 0; for(int i = head[x]; i; i = nxt[i]) { if(to[i] == fa) continue; dfs(to[i],x); if(dp[x][0] < dp[to[i]][0] + len[i]) { dp[x][1] = dp[x][0]; dp[x][0] = dp[to[i]][0] + len[i]; id[x] = i; } else if(dp[x][1] < dp[to[i]][0] + len[i]) dp[x][1] = dp[to[i]][0] + len[i]; } } void getdis(int x,int fa,ll dis) { dist[x] = 1LL * max(dis,dp[x][0]); for(int i = head[x]; i; i = nxt[i]) { if(to[i] == fa) continue; ll tmp = 0; if(id[x] == i) tmp = max(dis,dp[x][1]) + len[i]; else tmp = max(dis,dp[x][0]) + len[i]; getdis(to[i],x,tmp); } } ll mx[maxn<<2],mi[maxn<<2]; void build(int l,int r,int o) { if(l == r) { mx[o] = mi[o] = dist[l]; return; } int mid = (l + r) >> 1; build(l,mid,o << 1); build(mid + 1,r,o << 1 | 1); mx[o] = max(mx[o << 1],mx[o << 1 | 1]); mi[o] = min(mi[o << 1],mi[o << 1 | 1]); } int ql,qr; ll qmx,qmi; void que(int l,int r,int o) { if(ql <= l && qr >= r) { qmx = max(qmx,mx[o]); qmi = min(qmi,mi[o]); return; } int mid = (l + r) >> 1; if(mid >= ql) que(l,mid,o << 1); if(mid < qr) que(mid + 1,r,o << 1 | 1); } int main() { //freopen("e.in","r",stdin); //freopen("e.out","w",stdout); scanf("%d%d",&n,&m); cnt = 0; for(int i = 2; i <= n; i++) { int a,b; scanf("%d%d",&a,&b); addEdge(i,a,b); addEdge(a,i,b); } dfs(1,0); getdis(1,0,0); //for(int i = 1; i <= n; i++) cout<<dist[i]<<" "; //cout<<endl; build(1,n,1); int ans = 0; int l = 1,r = 1; while(r <= n) { ql = l; qr = r; qmx = 0; qmi = 1e18; que(1,n,1); if(qmx - qmi <= m) { ans = max(ans,r - l + 1); r++; } while(qmx - qmi > m) { l++; ql = l; ql = r; qmi = 1e18; qmx = 0LL; que(1,n,1); } } printf("%d\n",ans); return 0; }
HDU 5834 Magic boy Bi Luo with his excited tree
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 100005; int T; int n; int v[maxn]; int to[maxn<<1],w[maxn<<1],head[maxn],nxt[maxn<<1]; int not_back[maxn][2],id[maxn],back[maxn],ans[maxn]; int cnt; void addEdge(int a,int b,int c) { to[++cnt] = b; w[cnt] = c; nxt[cnt] = head[a]; head[a] = cnt; } void dfs(int x,int fa) { not_back[x][0] = not_back[x][1] = v[x]; id[x] = 0; back[x] = v[x]; for(int i = head[x]; i; i = nxt[i]) { if(to[i] == fa) continue; dfs(to[i],x); back[x] += max(back[to[i]] - 2 * w[i],0); } for(int i = head[x]; i; i = nxt[i]) { if(to[i] == fa) continue; int now = back[x] - max(0,back[to[i]] - 2 * w[i]) + max(0,not_back[to[i]][0] - w[i]); if(now > not_back[x][0]) { not_back[x][1] = not_back[x][0]; not_back[x][0] = now; id[x] = i; } else if(now > not_back[x][1]) not_back[x][1] = now; } } void solve(int x,int fa,int b,int g) { //cout<<endl; //cout<<x<<" "<<b<<" "<<g<<endl; ans[x] = max(not_back[x][0] + b,back[x] + g); for(int i = head[x]; i; i = nxt[i]) { if(to[i] == fa) continue; int tb,tg; if(id[x] == i) tg = max(0,not_back[x][1] - max(0,back[to[i]] - 2 * w[i])); else tg = max(0,not_back[x][0] - max(0,back[to[i]] - 2 * w[i])); tb = max(0,back[x] - max(0,back[to[i]] - 2 * w[i])); tg = max(0,max(g + tb - w[i],tg + b - w[i])); tb = max(0,b + tb - 2 * w[i]); solve(to[i],x,tb,tg); } } int main() { //freopen("f.in","r",stdin); //freopen("f.out","w",stdout); scanf("%d",&T); for(int kase = 1; kase <= T; kase++) { memset(head,0,sizeof head); scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%d",v + i); cnt = 0; for(int i = 0; i < n - 1; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); addEdge(a,b,c); addEdge(b,a,c); } //cout<<endl; dfs(1,0); //cout<<endl; solve(1,0,0,0); printf("Case #%d:\n",kase); for(int i = 1; i <= n; i++) printf("%d\n",ans[i]); } return 0; }
POJ 2152 Fire
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 1005; const int INF = 1 << 30; int T,n; int w[maxn],d[maxn]; int dis[maxn][maxn],best[maxn],dp[maxn][maxn];//第i个城市以第j个城市为防火负责点 int head[maxn],to[maxn<<1],nxt[maxn<<1],len[maxn<<1]; int cnt; void addEdge(int a,int b,int c) { to[++cnt] = b; len[cnt] = c; nxt[cnt] = head[a]; head[a] = cnt; } void init() { scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%d",w + i); for(int i = 1; i <= n; i++) scanf("%d",d + i); cnt = 0; memset(head,0,sizeof head); for(int i = 1; i <= n; i++) { best[i] = INF; for(int j = 1; j <= n; j++) dp[i][j] = INF; } for(int i = 1; i < n; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); addEdge(a,b,c); addEdge(b,a,c); } } void dfs(int x,int fa,int dist,int root) { dis[root][x] = dist; for(int i = head[x]; i; i = nxt[i]) { if(to[i] == fa) continue; dfs(to[i],x,dist + len[i],root); } } void solve(int u,int fa) { for(int i = 1; i <= n; i++) if(dis[u][i] <= d[u]) dp[u][i] = w[i]; for(int i = head[u]; i; i = nxt[i]) { int v = to[i]; if(v == fa) continue; solve(v,u); for(int j = 1; j <= n; j++) if(dis[u][j] <= d[u]) dp[u][j] += min(dp[v][j] - w[j],best[v]); } for(int i = 1; i <= n; i++) best[u] = min(best[u],dp[u][i]); } int main() { //freopen("g.in","r",stdin); //freopen("g.out","w",stdout); scanf("%d",&T); while(T--) { init(); for(int i = 1; i <= n; i++) dfs(i,0,0,i); solve(1,0); printf("%d\n",best[1]); } return 0; }
POJ 1741 Tree
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 10005; int n,k,m; int vis[maxn],f[maxn],son[maxn]; int dep[maxn],d[maxn]; int to[maxn<<1],len[maxn<<1],next[maxn<<1],head[maxn<<1]; void addEdge(int u,int v,int l) { to[++m] = v; len[m] = l; next[m] = head[u]; head[u] = m; } int root,sn; void getroot(int x,int fa) { son[x] = 1; f[x] = 0; for(int i = head[x]; i; i = next[i]) { if(to[i] == fa || vis[to[i]]) continue; getroot(to[i],x); son[x] += son[to[i]]; f[x] = max(f[x],son[to[i]]); } f[x] = max(f[x],sn - son[x]); if(f[root] > f[x]) root = x; } int cnt; void getdeep(int x,int fa) { d[cnt++] = dep[x]; for(int i = head[x]; i; i = next[i]) { if(to[i] == fa || vis[to[i]]) continue; dep[to[i]] = dep[x] + len[i]; getdeep(to[i],x); } } int cal(int x) { cnt = 0; getdeep(x,0); sort(d,d + cnt); int ret = 0; int i = 0, j = cnt - 1; while(i < j) { while(d[i] + d[j] > k && i < j) j--; ret += j - i; i++; } return ret; } int solve(int x) { dep[x] = 0; vis[x] = 1; int ans = cal(x); for(int i = head[x]; i; i = next[i]) { if(vis[to[i]]) continue; dep[to[i]] = len[i]; ans -= cal(to[i]); sn = son[to[i]]; root = 0; getroot(to[i],0); ans += solve(root); } return ans; } int main() { //freopen("h.in","r",stdin); //freopen("h.out","w",stdout); while(scanf("%d%d",&n,&k) == 2) { if(!n && !k) break; m = 0; memset(next,0,sizeof next); memset(head,0,sizeof head); for(int i = 1; i < n; i++) { int u,v,l; scanf("%d%d%d",&u,&v,&l); addEdge(u,v,l); addEdge(v,u,l); } memset(vis,0,sizeof vis); f[0] = 1e9; sn = n; root = 0; getroot(1,0); printf("%d\n",solve(root)); } return 0; }
TC SRM 693 DIV2 1000
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 105; const int INF = 1 << 29; int n,tot; int vis[maxn],nod[maxn]; int g[maxn][maxn]; int dp[maxn][3]; void dfs(int x,int fa) { int l1,l2; l1 = l2 = -1e9; dp[x][0] = dp[x][1] = dp[x][2] = 0; for(int i = 0; i < n; i++) { if(g[x][i] == 0 || i == fa) continue; dfs(i,x); int t1 = max(dp[i][0],dp[i][1]); int t2 = max(t1,dp[i][2]); int t3 = t1 - t2 + nod[i] + g[x][i]; dp[x][0] += t2; if(t3 >= l1) { l2 = l1; l1 = t3; } else if(t3 > l2) l2 = t3; } dp[x][1] = l1 + nod[x] + dp[x][0]; dp[x][2] = l1 + l2 + 2 * nod[x] + dp[x][0]; } class TreeAndCycle { public: int minimize(vector<int> costV,vector<int> pre,vector<int> costE) { n = costV.size(); memset(g,0,sizeof g); tot = 0; for(int i = 0; i < n; i++) { nod[i] = costV[i]; tot += 2 * costV[i]; } for(int i = 0; i < n - 1; i++) { tot += costE[i]; g[i+1][pre[i]] = g[pre[i]][i+1] = costE[i]; } dfs(0,0); return tot - max(dp[0][0],max(dp[0][1],dp[0][2])); } };