zoukankan      html  css  js  c++  java
  • P2515 [HAOI2010]软件安装

    Link

    题目描述

    现在我们的手头有 (N) 个软件,对于一个软件 (i) ,它要占用 (W_i)的磁盘空间,它的价值 (V_i)。我们希望从中选择一些软件安装到一台磁盘容量为 (M) 计算机上,使得这些软件的价值尽可能大(即 (V_i)的和最大)。

    但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件 (j)(包括软件 (j) 的直接或间接依赖)的情况下才能正确工作(软件 (i) 依赖软件 (j) )。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为 (0)

    我们现在知道了软件之间的依赖关系:软件 (i) 依赖软件 (D_i)。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则 (D_i=0),这时只要这个软件安装了,它就能正常工作。

    输入格式

    第1行:(N,M(0leq Nleq 100, 0leq Mleq 500))

    第2行:(W_1,W_2, ... W_i, ..., W_n (0leq W_ileq M))

    第3行:(V_1, V_2, ..., V_i, ..., V_n (0leq V_ileq 1000))

    第4行 (D_1, D_2, ..., D_i, ..., D_n (0leq D_ileq N, D_i≠i))

    输出格式

    一个整数,代表最大价值

    输入输出样例

    输入 #1

    3 10
    5 5 6
    2 3 4
    0 1 1
    

    输出 #1

    5
    

    一个比较显然的问题就是如果我们按照依赖关系建边的话,会得到一棵树(对没有依赖的点建个超级源)。

    剩下的就是树形背包的裸题啦。

    但,当你兴奋的交上去,认为又能水一道题的时候,却发现你 (WA) 了。

    因为 依赖关系可能会成为一个环,这就需要我们的第二个知识点, (tarjian)

    (tarjian) 缩完点之后,我们就可以得到一个有向无环图,在向没有依赖的点建个超级源,这就变成了我们熟悉的树上背包问题。

    一个需要注意的点就是,一定要在缩完点之后,在和超级源连边,否则可能会把超级源也给算进去。

    还有就是 (f) 数组一定要赋初值,我就在这里卡了好几回。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1010;
    int n,m,x,cnt,sum,tot,top,num;
    int head[N],hed[N],a[N],b[N],w[N],c[N];
    int low[N],dfn[N],sta[N],shu[N],du[N],f[110][510];
    bool vis[N];
    inline int read()
    {
    	int s = 0, w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
    	return s * w;
    }
    struct node
    {
    	int to,net;
    }e[N<<1],e2[N<<1];
    void add(int x,int y)
    {
    	e[++tot].to = y;
    	e[tot].net = head[x];
    	head[x] = tot;
    }
    void Add(int x,int y)
    {
    	e2[++sum].to = y;
    	e2[sum].net = hed[x];
    	hed[x] = sum;
    	
    }
    void tarjain(int x)
    {
    	dfn[x] = low[x] = ++num;
    	sta[++top] = x; vis[x] = 1;
    	for(int i = head[x]; i; i = e[i].net)
    	{
    		int to = e[i].to;
    		if(!dfn[to])
    		{
    			tarjain(to);
    			low[x] = min(low[x],low[to]);
    		}
    		else if(vis[to])
    		{
    			low[x] = min(low[x],dfn[to]);
    		}
    	}
    	if(dfn[x] == low[x])
    	{
    		cnt++; int y;
    		do
    		{
    			y = sta[top--];
    			shu[y] = cnt;
    			c[cnt] += a[y];
    			w[cnt] += b[y];
    			vis[y] = 0;
    		}while(x != y);
    	}
    }
    void rebuild()
    {
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = head[i]; j; j = e[j].net)
    		{
    			int to = e[j].to;
    			if(shu[i] != shu[to])
    			{
    				Add(shu[i],shu[to]);
    				du[shu[to]]++;
    			}
    		}
    	}
    	for(int i = 1; i <= cnt; i++)
    	{
    		if(du[i] == 0) Add(0,i);//没有依赖的点连向超级源
    	}
    }
    void dp(int x,int fa)
    {
    	for(int i = 0; i < c[x]; i++) f[x][i] = -1e9;//这里一定要赋初值
    	for(int i = c[x]; i <= m; i++) f[x][i] = w[x];
    	for(int i = hed[x]; i; i = e2[i].net)
    	{
    		int to = e2[i].to;
    		if(to == fa) continue;
    		dp(to,x);
    		for(int j = m; j >= 0; j--)//01背包
    		{
    			for(int k = 0; k <= j; k++)//k正序倒叙都可以
    			{
    //				cout<<to<<" "<<k<<" "<<f[to][k]<<endl;
    				f[x][j] = max(f[x][j],f[x][j-k]+f[to][k]);
    			}
    		}
    	}
    }
    int main()
    {
    	n = read(); m = read();
    	for(int i = 1; i <= n; i++) a[i] = read();
    	for(int i = 1; i <= n; i++) b[i] = read();
    	for(int i = 1; i <= n; i++)
    	{
    		x = read();
    		if(x == 0) continue;
    		else add(x,i);//连边
    	}
    	for(int i = 1; i <= n; i++)//缩点
    	{
    		if(!dfn[i]) tarjain(i);
    	}
    	rebuild();//重新建图
    	dp(0,0);//树上背包
    	printf("%d
    ",f[0][m]);
    	return 0;
    }
    
  • 相关阅读:
    sharepoint_study_10
    sharepoint_study_9
    sharepoint_study_8
    需要经常读的文章(长期更新)
    sharepoint_study_7
    sharepoint_study_目录学习笔记(长期更新)
    windows_study_2
    sharepoint_study_6
    sharepoint_study_5
    sharepoint_study_4
  • 原文地址:https://www.cnblogs.com/genshy/p/13658726.html
Copyright © 2011-2022 走看看