HAOI2010 软件安装

传送门

一开始我以为这道题是一个比较正常的分组背包,只不过原来做的题目的限制条件是数目,这次是有体积(软件所占空间)的限制,但是两者好像没什么差异……

于是我就仿着正常的分组背包写了一下,然后过了样例。我才不会告诉你我一开始结果全是0,因为我写错了

交上去一看只有10分……

回来发现原来这题并没有说是一棵树……orz,那我们来看一看每一个环,每个环里面所有的软件要么全选,要么全不选,所以直接看成一个强连通分量缩点,把体积和价值都合起来即可。就像炉石那张融合所以我们缩点,之后把所有入度为0的点向虚拟节点连边,之后开始正常DP。但是我一开始发现建出来的图是反的,这样就行不成树了。不过想起了tarjan求强连通分量的时候,因为我把树建成了有向图,所以肯定原来的起点现在还应该是起点,就把建图反了过来,之后就神奇的AC啦!

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 1005;
const int INF = 1000000009;
const ll mod = 1e9+7;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

struct node
{
    int next,to,from;
}e[M<<1];

int m,n,dp[M][M],v[M],x,y,head[M],ecnt,size[M],w[M],dfn[M],scc[M],idx,low[M],stack[M],top,cnt;
int rdeg[M],tot;
bool vis[M];

void add(int x,int y)
{
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    e[ecnt].from = x;
    head[x] = ecnt;
}

void tarjan(int x)
{
    low[x] = dfn[x] = ++idx;
    stack[++top] = x,vis[x] = 1;
    for(int i = head[x];i;i = e[i].next)
    {
    if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]);
    else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]);
    }
    if(low[x] == dfn[x])
    {
    int p;
    cnt++;
    while((p = stack[top--]))
    {
        scc[p] = cnt,vis[p] = 0,v[cnt] += v[p],w[cnt] += w[p];
        if(p == x) break;
    }
    }
}

void rebuild()
{
    rep(i,1,ecnt)
    {
    int r1 = scc[e[i].from],r2 = scc[e[i].to];
    if(r1 != r2) add(r2,r1),rdeg[r1]++;
    }
    rep(i,n+1,cnt)
    {
    dp[i][0] = v[i];
    if(!rdeg[i]) add(0,i);
    }
}

void dfs(int x,int fa)
{
    for(int i = head[x];i;i = e[i].next)
    {
    int t = e[i].to;
    if(t == fa) continue;
    dfs(t,x);
    per(j,m,1)
    {
        rep(p,0,j-w[t]) dp[x][j] = max(dp[x][j],dp[x][j-p-w[t]] + dp[t][p]);
    }
    //rep(j,0,m) printf("%d ",dp[x][j]);enter;
    //printf("#%d %d\n",x,dp[x][0]);
    }
}

int main()
{
    n = read(),m = read();
    rep(i,1,n) w[i] = read();
    rep(i,1,n) v[i] = read();
    rep(i,1,n)
    {
    x = read();
    if(x != 0) add(i,x);
    }
    cnt = n,tot = ecnt;
    rep(i,1,n) if(!dfn[i]) tarjan(i);
    rebuild();
    //rep(i,tot+1,ecnt) printf("%d %d\n",e[i].from,e[i].to);
    dfs(0,0);
    printf("%d\n",dp[0][m]);
    return 0;
}

 

posted @ 2018-10-19 08:08  CaptainLi  阅读(156)  评论(0编辑  收藏  举报