树形dp
题意:有很多人之间有上下级关系,求没有直接上下级关系去参加party的最多人数。
做法:dp[i][0]表示 结点 i 不参加,dp[i][1]表示 结点 i 参加。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #include<queue> 8 9 using namespace std; 10 11 #define inf 1e16 12 #define eps 1e-6 13 #define LL long long 14 #define ULL unsigned long long 15 #define MP make_pair 16 #define pb push_back 17 #define mod 1000000009 18 #define lson l, m, rt<<1 19 #define rson m+1, r, rt<<1|1 20 #define mnx 20050 21 22 int val[mnx], fst[mnx], nxt[mnx], fa[mnx], vv[mnx], e; 23 int dp[mnx][2]; 24 void init(){ 25 memset( fa, -1, sizeof(fa) ); 26 memset( fst, -1, sizeof(fst) ); 27 memset( dp, 0, sizeof(dp) ); 28 e = 0; 29 } 30 void add( int u, int v ){ 31 vv[e] = v, nxt[e] = fst[u], fst[u] = e++; 32 } 33 void dfs( int u ){ 34 dp[u][1] = val[u]; 35 for( int i = fst[u]; i != -1; i = nxt[i] ){ 36 int v = vv[i]; 37 dfs( v ); 38 dp[u][1] += dp[v][0]; 39 dp[u][0] += max( dp[v][1], dp[v][0] ); 40 } 41 } 42 int main(){ 43 int n; 44 while( scanf( "%d", &n ) != EOF ){ 45 init(); 46 for( int i = 1; i <= n; ++i ) 47 scanf( "%d", &val[i] ); 48 int u, v; 49 while( scanf( "%d%d", &u, &v ) != EOF ){ 50 if( u == 0 && v == 0 ) break; 51 add( v, u ); 52 fa[u] = v; 53 } 54 int s; 55 for( int i = 1; i <= n; ++i ) 56 if( fa[i] == -1 ){ 57 s = i; break; 58 } 59 dfs( s ); 60 printf( "%d\n", max( dp[s][0], dp[s][1] ) ); 61 } 62 return 0; 63 }
题意:求一个树上,每个结点 所能到达的最远距离是多少。
做法:dp[i][0]表示结点 i 儿子当中的最远距离,dp[i][1]表示结点 i 儿子结点当中的次长距离,dp[i][2]表示结点 i 到 除了i结点和它儿子结点 的其他所有点的最远距离。两次dfs一下就好。还有一种做法是找树的直径,然后每个结点到树的直径两端点的距离的最大值就是答案。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #include<map> 9 10 using namespace std; 11 12 #define mnx 20050 13 #define LL long long 14 #define inf 0x3f3f3f3f 15 #define MP make_pair 16 #define lson l, m, rt << 1 17 #define rson m+1, r, rt << 1 | 1 18 #define mod 9973 19 20 int fst[mnx], nxt[mnx], vv[mnx], cost[mnx], e; 21 void init(){ 22 memset( fst, -1, sizeof(fst) ); 23 e = 0; 24 } 25 void add( int u, int v, int c ){ 26 vv[e] = v, nxt[e] = fst[u], cost[e] = c, fst[u] = e++; 27 } 28 int dep[mnx], dp[mnx][3]; 29 bool cmp( int a, int b ){ 30 return a > b; 31 } 32 void update( int u, int val ){ 33 dp[u][2] = val; 34 sort( dp[u], dp[u] + 3, cmp ); 35 } 36 void dfs1( int u, int p ){ 37 for( int i = fst[u]; i != -1; i = nxt[i] ){ 38 int v = vv[i], c = cost[i]; 39 if( v == p ) continue; 40 dfs1( v, u ); 41 update( u, dp[v][0] + c ); 42 } 43 } 44 void dfs2( int u, int p ){ 45 for( int i = fst[u]; i != -1; i = nxt[i] ){ 46 int v = vv[i], c = cost[i]; 47 if( v == p ) continue; 48 // cout << dp[v][0] << " " << c << " " << dp[u][0] << endl; 49 if( dp[v][0] + c == dp[u][0] ) 50 dp[v][2] = max( dp[v][2], max( dp[u][2] + c, dp[u][1] + c ) ); 51 else 52 dp[v][2] = max( dp[v][2], max( dp[u][2] + c, dp[u][0] + c ) ); 53 dfs2( v, u ); 54 } 55 } 56 int n; 57 void debug(){ 58 for( int i = 1; i <= n; ++i ){ 59 printf( "%d: %d\n", i, dp[i][2] ); 60 } 61 } 62 int main(){ 63 while( scanf( "%d", &n ) != EOF ){ 64 init(); 65 for( int i = 2; i <= n; ++i ){ 66 int u, c; 67 scanf( "%d%d", &u, &c ); 68 add( i, u, c ), add( u, i, c ); 69 } 70 memset( dp, 0, sizeof(dp) ); 71 dfs1( 1, -1 ); 72 dfs2( 1, -1 ); 73 // debug(); 74 for( int i = 1; i <= n; ++i ){ 75 printf( "%d\n", max( dp[i][0], dp[i][2] ) ); 76 } 77 } 78 return 0; 79 }
题意:给一棵树,树有边权.现在要在一些点上建立消防站,每个点建站都有个w[i],如果不在当前的点上建站,也要依赖其他的消防站,并且距离不超过d[i]。求符合上述条件的最小费用建站方案。
做法:dp[i][j]表示 i 结点所在的子树,必须在 j 结点建立消防站的花费。best[i]表示 i 结点所在的子树,满足条件时的最少花费。
状态转移:dp[u][i] = w[i]; dp[u][i] += min( best[v], dp[v][i] - w[i] );
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #include<map> 9 10 using namespace std; 11 12 #define mnx 2050 13 #define LL long long 14 #define inf 0x3f3f3f3f 15 #define MP make_pair 16 #define lson l, m, rt << 1 17 #define rson m+1, r, rt << 1 | 1 18 #define mod 9973 19 20 int fst[mnx], nxt[mnx], vv[mnx], cost[mnx], e; 21 void init(){ 22 memset( fst, -1, sizeof(fst) ); 23 e = 0; 24 } 25 void add( int u, int v, int c ){ 26 vv[e] = v, nxt[e] = fst[u], cost[e] = c, fst[u] = e++; 27 } 28 int d[mnx], dis[mnx], w[mnx], dp[mnx][mnx], best[mnx], n; 29 void getdis( int dist, int u, int p ){ 30 dis[u] = dist; 31 for( int i = fst[u]; i != -1; i = nxt[i] ){ 32 int v = vv[i], c = cost[i]; 33 if( v == p ) continue; 34 getdis( dist + c, v, u ); 35 } 36 } 37 void dfs( int u, int p ){ 38 for( int i = fst[u]; i != -1; i = nxt[i] ){ 39 int v = vv[i]; 40 if( v == p ) continue; 41 dfs( v, u ); 42 } 43 getdis( 0, u, -1 ); 44 best[u] = inf; 45 for( int i = 1; i <= n; ++i ){ 46 if( dis[i] > d[u] ) dp[u][i] = inf; 47 else{ 48 dp[u][i] = w[i]; 49 for( int j = fst[u]; j != -1; j = nxt[j] ){ 50 int v = vv[j]; 51 if( v == p ) continue; 52 dp[u][i] += min( best[v], dp[v][i] - w[i] ); 53 } 54 } 55 best[u] = min( best[u], dp[u][i] ); 56 } 57 } 58 int main(){ 59 // freopen( "tt.txt", "r", stdin ); 60 int cas; 61 scanf( "%d", &cas ); 62 while( cas-- ){ 63 init(); 64 scanf( "%d", &n ); 65 for( int i = 1; i <= n; ++i ) 66 scanf( "%d", &w[i] ); 67 for( int i = 1; i <= n; ++i ) 68 scanf( "%d", &d[i] ); 69 for( int i = 1; i < n; ++i ){ 70 int u, v, c; 71 scanf( "%d%d%d", &u, &v, &c ); 72 add( u, v, c ), add( v, u, c ); 73 } 74 dfs( 1, -1 ); 75 printf( "%d\n", best[1] ); 76 } 77 return 0; 78 }