切題ing!!!!!php
HDU 2196 Anniversary partynode
經典樹形DP,之前寫的太搓了,終於學會簡單寫法了....ios
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <map> #include <queue> #include <set> #include <vector> #define MOD 100000000 #define LL __int64 using namespace std; int dp[7000][2]; struct node { int u,v,next; }edge[7000]; int first[7000]; int flag[7000]; int p[7000]; int t; void CL() { t = 0; memset(first,-1,sizeof(first)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } int dfs(int x,int st,int fa) { int sum = 0,i,v; if(dp[x][st] != -1) return dp[x][st]; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(v == fa) continue; dfs(v,0,x); dfs(v,1,x); if(st == 0) sum += max(dp[v][0],dp[v][1]); else sum += dp[v][0]; } if(st == 1) return dp[x][1] = sum + p[x]; else return dp[x][0] = sum; } int main() { int n,i,u,v; while(scanf("%d",&n)!=EOF) { CL(); memset(dp,-1,sizeof(dp)); for(i = 1;i <= n;i ++) { scanf("%d",&p[i]); } memset(flag,0,sizeof(flag)); for(;;) { scanf("%d%d",&u,&v); if(!u&&!v) break; add(v,u); flag[u] = 1; } for(i = 1;i <= n;i ++) { if(!flag[i]) add(0,i); } printf("%d\n",dfs(0,0,-1)); } return 0; }
經典兩次DFS,樹形DP,也能夠用最長路來作,我之前會的,忘了好多...oop
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <map> #include <queue> #include <set> #include <vector> #define MOD 100000000 #define LL __int64 using namespace std; int dp[10001][2]; int ans[10001]; int flag[10001]; struct node { int u,v,w,next; }edge[20001]; int t; int first[10001]; void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } void dfs1(int x) { int i,v,max1 = 0,max2 = 0; flag[x] = 1; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(flag[v]) continue; dfs1(v); if(max1 < dp[v][0] + edge[i].w) { max2 = max1; max1 = dp[v][0] + edge[i].w; } else if(max1 == dp[v][0] + edge[i].w) max2 = dp[v][0] + edge[i].w; else if(max2 < dp[v][0] + edge[i].w) max2 = dp[v][0] + edge[i].w; } dp[x][0] = max1; dp[x][1] = max2; } void dfs2(int x,int fa) { int i,v; flag[x] = 1; ans[x] = max(dp[x][0],fa); for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(flag[v]) continue; if(dp[x][0] == dp[v][0] + edge[i].w) dfs2(v,max(fa,dp[x][1])+edge[i].w); else dfs2(v,max(fa,dp[x][0])+edge[i].w); } } int main() { int i,n,v,w; while(scanf("%d",&n)!=EOF) { CL(); for(i = 2;i <= n;i ++) { scanf("%d%d",&v,&w); add(v,i,w); add(i,v,w); } memset(flag,0,sizeof(flag)); dfs1(1); //for(i = 1;i <= n;i ++) //printf("%d %d\n",dp[i][0],dp[i][1]); memset(flag,0,sizeof(flag)); dfs2(1,0); for(i = 1;i <= n;i ++) printf("%d\n",ans[i]); } return 0; }
之前作的時候,看錯題了...這題是把全部的路,放一個士兵看守,那麼若是根不放士兵,那麼全部的子節點都要放。spa
#include <cstdio> #include <cstring> #include <string> #include <iostream> using namespace std; #define INF 100000000 struct node { int u,v,next; }edge[1501]; int dp[1501][2]; int flag[1501]; int t; int first[1501]; void CL() { t = 0; memset(flag,0,sizeof(flag)); memset(dp,0,sizeof(dp)); memset(first,-1,sizeof(first)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } void dfs(int x) { int i,v; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; dfs(v); } for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; dp[x][1] += min(dp[v][0],dp[v][1]); dp[x][0] += dp[v][1]; } dp[x][1] ++; } int main() { int i,j,n,m,u,v; while(scanf("%d",&n)!=EOF) { CL(); for(i = 1;i <= n;i ++) { scanf("%d:(%d)",&u,&m); for(j = 1;j <= m;j ++) { scanf("%d",&v); flag[v] = 1; add(u,v); } } for(i = 0;i < n;i ++) { if(!flag[i]) { dfs(i); printf("%d\n",min(dp[i][0],dp[i][1])); break; } } } return 0; }
水題....orm
#include <cstdio> #include <cstring> #include <string> #include <iostream> using namespace std; #define INF 100000000 struct node { int u,v,next; } edge[120001]; int first[51000]; int dp[51000]; int dis[51000]; int t; void CL() { t = 1; memset(first,-1,sizeof(first)); memset(dp,0,sizeof(dp)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } int n; void dfs(int x,int fa) { int i,v,temp = 1; for(i = first[x]; i != -1; i = edge[i].next) { v = edge[i].v; if(v == fa) continue; dfs(v,x); temp += dp[v]; } dp[x] = temp; dis[x] = n - temp; for(i = first[x]; i != -1; i = edge[i].next) { v = edge[i].v; if(v == fa) continue; dis[x] = max(dis[x],dp[v]); } } int main() { int i,u,v; while(scanf("%d",&n)!=EOF) { CL(); for(i = 0; i < n-1; i ++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1,-1); int ans = INF; for(i = 1; i <= n; i ++) { ans = min(ans,dis[i]); } int flag = 0; for(i = 1; i <= n; i ++) { if(ans == dis[i]) { if(flag) printf(" "); flag = 1; printf("%d",i); } } printf("\n"); } return 0; }
POJ 1155 TELEblog
分組揹包,1Y哦,注意背的順序,調了小會。。
#include <cstdio> #include <cstring> #include <string> #include <iostream> using namespace std; #define INF 100000000 struct node { int u,v,w,next; } edge[120001]; int dp[3001][3001]; int p[3001]; int lf[3001]; int first[3001]; int t,n,m; void CL() { t = 1; memset(first,-1,sizeof(first)); memset(p,0,sizeof(p)); memset(lf,0,sizeof(lf)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } void dfs(int x) { int i,j,k,v,w,sum = 0; if(first[x] == -1) { dp[x][1] = p[x]; lf[x] = 1; return ; } for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; dfs(v); sum += lf[v]; } for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; w = edge[i].w; for(j = sum;j >= 1;j --) { for(k = 1;k <= min(j,lf[v]);k ++) { if(dp[v][k] == -INF) continue; dp[x][j] = max(dp[x][j],dp[v][k] + dp[x][j-k] - w); } } } lf[x] = sum; } int main() { int i,j,k,v,w; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 1;i <= n;i ++) { for(j = 1;j <= n;j ++) dp[i][j] = -INF; } for(i = 1;i <= n-m;i ++) { scanf("%d",&k); for(j = 1;j <= k;j ++) { scanf("%d%d",&v,&w); add(i,v,w); } } for(i = n-m+1;i <= n;i ++) { scanf("%d",&p[i]); } dfs(1); for(i = m;i >= 1;i --) { if(dp[1][i] >= 0) break; } printf("%d\n",i); } return 0; }
分組揹包,這個題意坑啊。若是想往下走,必須把根節點的bug消滅。
#include <cstdio> #include <cstring> #include <string> #include <iostream> using namespace std; #define INF 100000000 struct node { int u,v,next; } edge[100001]; int p[101]; int w[101]; int first[101]; int flag[101]; int dp[101][101]; int t,n,m; void CL() { t = 1; memset(first,-1,sizeof(first)); memset(dp,0,sizeof(dp)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } void dfs(int x) { int i,j,k,v,pre; flag[x] = 1; pre = (p[x]+19)/20; for(i = pre;i <= m;i ++) dp[x][i] = w[x]; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(flag[v]) continue; dfs(v); for(j = m;j >= pre;j --) { for(k = 1;k + pre <= j;k ++)//保證j-k>=pre,保證能消滅bug { dp[x][j] = max(dp[x][j],dp[v][k] + dp[x][j-k]); } } } } int main() { int i,u,v; while(scanf("%d%d",&n,&m)!=EOF) { if(n < 0) break; CL(); memset(flag,0,sizeof(flag)); for(i = 1;i <= n;i ++) { scanf("%d%d",&p[i],&w[i]); } for(i = 1;i < n;i ++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } if(m == 0) { printf("0\n"); continue; } dfs(1); printf("%d\n",dp[1][m]); } return 0; }
挺簡單的,注意 順序和範圍。
#include <cstdio> #include <cstring> #include <string> #include <iostream> using namespace std; #define INF 100000000 struct node { int u,v,next; }edge[1001]; int first[301]; int dp[301][301]; int p[301]; int t,m; void CL() { t = 1; memset(first,-1,sizeof(first)); memset(dp,0,sizeof(dp)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } void dfs(int x) { int i,j,k,v; for(i = 1;i <= m;i ++) dp[x][i] = p[x]; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; dfs(v); for(j = m;j >= 1;j --) { for(k = 1;k < j;k ++) dp[x][j] = max(dp[x][j],dp[v][k] + dp[x][j-k]); } } } int main() { int n,i; while(scanf("%d%d",&n,&m)!=EOF) { if(n == 0&&m == 0) break; CL(); m ++; for(i = 1;i <= n;i ++) { int u,v; scanf("%d%d",&u,&v); p[i] = v; add(u,i); } dfs(0); printf("%d\n",dp[0][m]); } return 0; }
三種轉移,少了一種....
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <vector> using namespace std; #define LL long long struct node { int u,v,next; }edge[1000]; int p[300]; int first[300]; int flag[300]; int dp[300][300][2]; int t,n,m; void CL() { t = 1; memset(flag,0,sizeof(flag)); memset(first,-1,sizeof(first)); memset(dp,0,sizeof(dp)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t ++; } void dfs(int x) { int i,v,j,k; flag[x] = 1; dp[x][0][0] = dp[x][0][1] = p[x]; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(flag[v]) continue; dfs(v); for(j = m;j >= 0;j --) { for(k = 0;k <= j;k ++) { if(j-1-k >= 0) dp[x][j][0] = max(dp[x][j][0],dp[x][j-1-k][1]+dp[v][k][0]); if(j-2-k >= 0) { dp[x][j][0] = max(dp[x][j][0],dp[x][j-2-k][0] + dp[v][k][1]); dp[x][j][1] = max(dp[x][j][1],dp[x][j-2-k][1]+dp[v][k][1]); } } } } } int main() { int u,v,i; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 1;i <= n;i ++) scanf("%d",&p[i]); for(i = 1;i < n;i ++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1); int ans = 0; for(i = 0;i <= m;i ++) { ans = max(ans,dp[1][i][0]); ans = max(ans,dp[1][i][1]); } printf("%d\n",ans); } return 0; }
HDU 3586 Information Disturbing
亂搞。
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <cstdlib> #include <algorithm> #include <queue> using namespace std; #define INF 1000000000 struct node { int u,v,w,next; }edge[2001]; int first[1001]; int flag[1001]; int dp[1001][1001]; int t,maxz; void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } void dfs(int x,int fa) { int v,i,j,temp,sum,num = 0; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(v == fa) continue; dfs(v,x); num ++; } if(num == 0) return ; for(i = 1;i <= maxz;i ++) { sum = 0; for(j = first[x];j != -1;j = edge[j].next) { v = edge[j].v; if(v == fa) continue; if(i >= edge[j].w) temp = min(edge[j].w,dp[v][i]); else temp = dp[v][i]; if(temp == INF) { dp[x][i] = INF; break; } sum += temp; } if(j == -1) dp[x][i] = sum; } } int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { if(n == 0&&m == 0) break; CL(); maxz = 0; for(i = 1;i < n;i ++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); maxz = max(maxz,w); add(u,v,w); add(v,u,w); } for(i = 1;i <= n;i ++) { for(j = 1;j <= maxz;j ++) dp[i][j] = INF; } dfs(1,-1); for(i = 1;i <= maxz;i ++) { if(dp[1][i] <= m) break; } if(i == maxz + 1) printf("-1\n"); else printf("%d\n",i); } return 0; }
HDU 4276 The Ghost Blows Light
感受和吃蘋果那個有點像,想了一個4維DP,而後妥妥的TLE了,而後想了想發現1到n,是必須走的,分着處理出來,減去這條必須走的,繼續分組揹包,寫的很麻煩dp[i][j],表示以i爲根花費j的回到i獲得最大價值。
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #include <map> using namespace std; int dp[101][501]; int flag[101]; int first[101]; int pre[101]; int p[101]; int sum[101]; int t,n,m; struct node { int u,v,w,next; }edge[201]; void CL() { t = 1; memset(first,-1,sizeof(first)); memset(flag,0,sizeof(flag)); memset(sum,0,sizeof(sum)); memset(dp,0,sizeof(dp)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } void find(int x,int fa) { int i,v; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(v == fa) continue; pre[v] = x; sum[v] = sum[x] + edge[i].w; find(v,x); } } void dfs(int x) { int i,v,w,j,k; flag[x] = 1; dp[x][0] = p[x]; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; w = edge[i].w; if(flag[v]) continue; if(v == pre[x]) continue; dfs(v); for(j = m;j >= 0;j --) { for(k = 0;k <= j;k ++) { if(j-k-2*w >= 0) dp[x][j] = max(dp[x][j],dp[x][j-k-2*w] + dp[v][k]); } } } } int main() { int u,v,w,i,k; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 1;i < n;i ++) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } for(i = 1;i <= n;i ++) scanf("%d",&p[i]); find(1,-1); if(sum[n] > m) { printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); continue; } int x = n; m -= sum[n]; while(1) { dfs(x); for(i = m;i >= 0;i --) { for(k = 0;k <= i;k ++) { dp[0][i] = max(dp[0][i],dp[0][i-k]+dp[x][k]); } } if(x == 1) break; x = pre[x]; } int maxz = 0; for(i = 0;i <= m;i ++) maxz = max(maxz,dp[0][i]); printf("%d\n",maxz); } return 0; } /* 3 0 1 2 2 1 3 0 1 2 3 */
尚大嬸 說這題很水。。。必須水過去,dp[i][0]表示i點子樹的道路沒有被封,dp[i][1]表示i點在子樹已經有道路被封了。
dp[i][0] = sum(dp[v][1]);
dp[i][1] = sum(dp[v][1]) + max(dp[v][0]-dp[v][1]) + 1;
找路徑扯淡一點,爆棧,加代碼就水過了。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #include <map> using namespace std; int dp[300001][2]; int first[300001]; int flag[300001]; int t; struct node { int u,v,next; }edge[300001]; int qu[300001]; int qv[300001]; int o[300001]; void CL() { t = 1; memset(o,0,sizeof(o)); memset(first,-1,sizeof(first)); memset(flag,0,sizeof(flag)); memset(dp,0,sizeof(dp)); } void add(int u,int v) { edge[t].u = u; edge[t].v = v; edge[t].next = first[u]; first[u] = t++; } void dfs(int x) { int i,v,maxz = -10000000,tf; flag[x] = 1; tf = 1; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(flag[v]) continue; tf = 0; dfs(v); dp[x][0] += dp[v][1]; maxz = max(maxz,dp[v][0]-dp[v][1]); } if(tf) { dp[x][0] = dp[x][1] = 0; return ; } dp[x][1] = dp[x][0] + maxz + 1; } void find(int x,int y,int fa) { int i,v,maxz = -1000000,tf = 1,z; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(v == fa) continue; maxz = max(maxz,dp[v][0]-dp[v][1]); tf = 0; } if(tf) return ; z = 1; for(i = first[x];i != -1;i = edge[i].next) { v = edge[i].v; if(v == fa) continue; if(y == 0) find(v,1,x); else { if(maxz == dp[v][0]-dp[v][1]&&z) { find(v,0,x); o[(i+1)/2] = 1; z = 0; } else find(v,1,x); } } } int main() { int n,m,i; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 1;i <= m;i ++) { int u,v; scanf("%d%d",&u,&v); qu[i] = u; qv[i] = v; add(u,v); add(v,u); } dfs(1); printf("%d\n",dp[1][1]); find(1,1,-1); for(i = 1;i <= m;i ++) { if(o[i]) printf("%d %d\n",qu[i],qv[i]); } } return 0; }