Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1628 Solved: 635
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
第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 )
一个整数,代表最大价值。
3 10
5 5 6
2 3 4
0 1 1
5
Day2
这题显然如果有环,我们把其缩成一个点来处理,要么全部买,要么全部不买,然后加一个超级源到所有没有要求的点,然后跑超级源的树上DP就可以了
233调了好久,%黄学长的代码
但是我可以hack黄学长啊,黄学长这组数据要挂233
3 100
5 0 3
0 2 0
0 1 1
#include
using namespace std;
const int MAXN = 500 + 10;
int timer, dfn[MAXN], low[MAXN], tail, sta[MAXN], top, cnt, scc[MAXN];
int w[MAXN], val[MAXN], head[MAXN], N, M, tmp, sv[MAXN], sw[MAXN], in[MAXN];
int h[MAXN], dp[MAXN][MAXN];
struct Edge{ int to, nxt; } edge[ MAXN * 2 ];
struct Line{ int to, nxt; } line[ MAXN * 2 ];
void add_line( int from, int to ) {
line[++tail].nxt= head[from];
line[tail].to = to;
head[from] = tail;
}
bool vis[MAXN];
void Tarjan( int u ) {
++timer; dfn[u] = low[u] = timer;
vis[u] = true; sta[++top] = u;
for( register int i = head[u]; i; i = line[i].nxt ) {
int v = line[i].to;
if( !dfn[v] ) {
Tarjan( v );
low[u] = min( low[u], low[v] );
} else if( vis[v] ) low[u] = min( low[u], dfn[v] );
}
if( dfn[u] == low[u] ) {
cnt++;
scc[u] = cnt; vis[u] = false;
sw[cnt] += w[u];
sv[cnt] += val[u];
while( sta[top] != u ) {
vis[sta[top]] = false;
scc[sta[top]] = cnt;
sw[cnt] += w[sta[top]];
sv[cnt] += val[sta[top]];
top--;
}
top--;
}
}
void insert( int from, int to ) {
edge[++tail].nxt = h[from];
edge[tail].to = to;
in[to] = 1;
h[from] = tail;
}
bool connec[105][105] ;
void rebuild( ) { tail = 0;
for( register int i = 1; i <= N; i++ )
for( register int j = head[i]; j; j = line[j].nxt )
if( scc[line[j].to] != scc[i] && !connec[scc[i]][scc[line[j].to]] )
insert( scc[i], scc[line[j].to] ) ,
connec[scc[i]][scc[line[j].to]] = true ;
}
void dpp( int u ) {
for( register int i = h[u]; i; i = edge[i].nxt ) {
//printf( "%d to %d\n" , u , edge[i].to ) ;
dpp( edge[i].to );
for( register int j = M - sw[u]; j >= 0; j-- )
for( register int k = 0 ; k <= j ; k++ )
//改法是反向枚举k
dp[u][j] = max( dp[u][j], dp[u][k] + dp[edge[i].to][ j - k ] );
}
for( register int i = M; i >= 0; i-- )
if( i >= sw[u] ) dp[u][i] = dp[u][ i - sw[u] ] + sv[u];
else dp[u][i] = 0;
}
int main( ) {
scanf( "%d%d", &N, &M );
for( register int i = 1; i <= N; i++ ) scanf( "%d", &w[i] );
for( register int i = 1; i <= N; i++ ) scanf( "%d", &val[i] );
for( register int i = 1; i <= N; i++ ) { scanf( "%d", &tmp ); if( tmp ) add_line( tmp, i ); }
for( register int i = 1; i <= N; i++ )
if( !dfn[i] ) Tarjan( i );
//printf( "cnt = %d\n" , cnt ) ;
//printf( "top = %d\n" , top ) ;
rebuild( );
//printf( "sv :: %d %d %d\n" , sv[1] , sv[2] , sv[3] ) ;
for( register int i = 1; i <= cnt; i++ )
if( !in[i] ) insert( cnt + 1, i );
dpp( cnt + 1 );
printf( "%d\n", dp[ cnt + 1 ][M] );
return 0;
}
/*
3 100
5 0 3
0 2 0
0 1 1
*/