bzoj 2427 HAOI 2010 软件安装 (dp+tarjan缩点)
2017-06-05 09:51
489 查看
题面大概如此:
Description
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Input
第1行:N, M (0<=N<=100, 0<=M<=500)
第2行:W1, W2, … Wi, …, Wn (0<=Wi<=M )
第3行:V1, V2, …, Vi, …, Vn (0<=Vi<=1000 )
第4行:D1, D2, …, Di, …, Dn (0<=Di<=N, Di≠i )
Output
一个整数,代表最大价值。
Sample Input
3 10
5 5 6
2 3 4
0 1 1
Sample Output
5
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2427
这道题明显是树上dp,依赖的背包问题。但是题目比较坑的是这个题目允许有环出现,也就是1依赖2,2依赖1则,环上物体要么全选,要么全部不选,所以我们预处理缩点,重新建图,再建一个虚根节点,连接所有入度为0的点,跑一遍dp就可以了。
2427 Accepted 1540 kb 124 ms C++/Edit 3146 B 2017-06-05 09:44:45
AC代码:
Description
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Input
第1行:N, M (0<=N<=100, 0<=M<=500)
第2行:W1, W2, … Wi, …, Wn (0<=Wi<=M )
第3行:V1, V2, …, Vi, …, Vn (0<=Vi<=1000 )
第4行:D1, D2, …, Di, …, Dn (0<=Di<=N, Di≠i )
Output
一个整数,代表最大价值。
Sample Input
3 10
5 5 6
2 3 4
0 1 1
Sample Output
5
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2427
这道题明显是树上dp,依赖的背包问题。但是题目比较坑的是这个题目允许有环出现,也就是1依赖2,2依赖1则,环上物体要么全选,要么全部不选,所以我们预处理缩点,重新建图,再建一个虚根节点,连接所有入度为0的点,跑一遍dp就可以了。
2427 Accepted 1540 kb 124 ms C++/Edit 3146 B 2017-06-05 09:44:45
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define N 505 #define INF 0x3f3f3f3f using namespace std; struct Edge{ int v, next; }; Edge e[2 * N], e2[2 * N];//e为最开始的图,e2为重建的图 int num, head , num2, head2 , in ; void adde1( int i, int j ) { e[++num].v = j; e[num].next = head[i]; head[i] = num; } void adde2( int i, int j ) { in[j] = 1; e2[++num2].v = j; e2[num2].next = head2[i]; head2[i] = num2; } int inde, dfn , low , instack , stack , top;//tarjan int n, m, w , v , x, f[105][505]; int scc, sv , sw , belong ; void tarjan( int u ) {//找环 inde++; dfn[u] = low[u] = inde; instack[u] = 1; stack[++top] = u; for ( int i = head[u]; i; i = e[i].next ) { int v = e[i].v; if ( !dfn[v] ) { tarjan(v); low[u] = min(low[u], low[v]); } else if (instack[v]) low[u] = min(low[u], dfn[v]); } if( low[u] == dfn[u] ) { scc++; int now = 0; while( now != u ) { now = stack[top--]; instack[now] = 0; belong[now] = scc; sv[scc] += v[now]; sw[scc] += w[now]; } } } void dp( int u ) {//树上dp这里我给出3种写法,大概都差不多(⊙﹏⊙)b for ( int i = 0; i < sw[u]; i++ ) f[u][i] = 0; for ( int i = sw[u]; i <= m; i++ ) f[u][i] = sv[u]; for ( int i = head2[u]; i; i = e2[i].next ) { int v = e2[i].v; dp(v); for ( int k = m; k >= sw[u]; k-- ) for ( int j = 0; j <= k-sw[u]; j++ ) f[u][k] = max(f[u][k], f[u][k-j]+f[v][j]); } } /* void dp( int u ) { for ( int i = 0; i < sw[u]; i++ ) f[u][i] = 0; for ( int i = sw[u]; i <= m; i++ ) f[u][i] = sv[u]; for ( int i = head2[u]; i; i = e2[i].next ) { int v = e2[i].v; dp(v); for ( int k = m-sw[u]; k >= 0; k-- ) for ( int j = 0; j <= k; j++ ) f[u][k+sw[u]] = max(f[u][k+sw[u]], f[u][k+sw[u]-j]+f[v][j]); } } */ /* void dp( int u ) { for(int i = head2[u]; i; i = e2[i].next) { int v = e2[i].v; dp(v); for(int j = m - sw[u]; j>= 0; j--) { for(int k = 0; k <= j; k++) f[u][j]=max(f[u][j],f[u][k]+f[v][j-k]); } } for(int j = m; j >= 0; j--) { if(j >= sw[u]) f[u][j] = f[u][j-sw[u]] + sv[u]; else f[u][j] = 0; } } */ int main() {//主程序都看得懂吧O(∩_∩)O哈! scanf( "%d%d", &n, &m ); for ( int i = 1; i <= n; i++ ) scanf( "%d", w + i ); for ( int i = 1; i <= n; i++ ) scanf( "%d", v + i ); for ( int i = 1; i <= n; i++ ) { scanf( "%d", &x ); if ( x != 0 ) adde1( x, i ); } for ( int i = 1; i <= n; i++ ) if ( !dfn[i] ) tarjan(i); for ( int i = 1; i <= n; i++ ) for ( int j = head[i]; j; j = e[j].next ) { int v = e[j].v; if ( belong[v] != belong[i] ) adde2(belong[i], belong[v]); } for ( int i = 1; i <= scc; i++ ) if ( !in[i] ) adde2(scc+1, i); dp(scc+1); printf( "%d\n", f[scc+1][m] ); return 0; }
相关文章推荐
- bzoj 2427: [HAOI2010]软件安装(tarjan缩点+树形dp)
- BZOJ 2427: [HAOI2010]软件安装 Tarjan缩点 + DP
- [BZOJ2427][HAOI2010]软件安装(Tarjan+树形&背包DP)
- [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)
- BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP
- bzoj 2427: [HAOI2010]软件安装【tarjan+树形dp】
- BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP
- 【bzoj2427】【HAOI2010】【软件安装】【缩点+dp】
- BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP
- BZOJ 2427 HAOI 2010 软件安装 Tarjan+树上DP
- [bzoj2427][HAOI2010]软件安装(树形dp+tarjan)
- [bzoj2427][HAOI2010]软件安装 Tarjan+树形DP
- 【BZOJ2427】【HAOI2010】软件安装 tarjan+树形背包DP
- BZOJ 2427: [HAOI2010]软件安装|树形动规|tarjan
- BZOJ 2427: [HAOI2010]软件安装( dp )
- 【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包
- 【bzoj2427】[HAOI2010]软件安装 Tarjan+树形背包dp
- [HAOI2010][BZOJ2427] 软件安装|tarjan|树型dp
- |BZOJ 2427|树形DP|强连通分量|[HAOI2010]软件安装
- bzoj2427 [HAOI2010]软件安装 ( 树形背包 + tarjan )