BZOJ 2427: [HAOI2010]软件安装 Tarjan缩点 + DP

来源:互联网 发布:知乎回答如何取消匿名 编辑:程序博客网 时间:2024/05/21 18:34

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1628 Solved: 635

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

HINT

Source

Day2


这题显然如果有环,我们把其缩成一个点来处理,要么全部买,要么全部不买,然后加一个超级源到所有没有要求的点,然后跑超级源的树上DP就可以了
233调了好久,%黄学长的代码
但是我可以hack黄学长啊,黄学长这组数据要挂233

3 100
5 0 3
0 2 0
0 1 1


#include <bits/stdc++.h>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 1005 0 30 2 00 1 1 */

这里写图片描述

阅读全文
0 0
原创粉丝点击