并查集与背包的结合

       前两次已经说了并查集和背包的一些内容,可以去看我之前发的关于并查集和背包的文章,这里就是结合两个知识点来写题目。话不多说,上题目。下面是一个洛谷p1455的一个题目。

       第一行输入三个整数,n,m,w,表示有 n 朵云,m 个搭配和你现有的钱的数目。第二行至n+1 行,每行有两个整数, ci​,di​,表示第 i 朵云的价钱和价值。第 n+2 至 n+1+m 行 ,每行有两个整数 ui​,vi​。表示买第 ui​ 朵云就必须买第vi​ 朵云,同理,如果买第 vi​ 朵就必须买第 ui​ 朵。最后就是输出可以获得的最大价值。

这里使用了结构体k数组输入第二行到n+1行的两个整数分别为k[i].x和k[i].y,接下来主函数使用并查集的内容,这里也定义了两个函数分别为fun1和fun2,代码如下:

int fun2(int x)
{
    if(fa[x]==x)
        return x;
    else fa[x]=fun2(fa[x]);
        return fa[x];
}
void fun1(int x,int y)
{
    int xx=fun2(x);
    int yy=fun2(y);
    if(xx!=yy)
    {
        k[xx].x=k[xx].x+k[yy].x;
        k[xx].y=k[xx].y+k[yy].y;
        fa[yy]=xx;
    }
}

大家可能不理解以下部分:

k[xx].x=k[xx].x+k[yy].x;
k[xx].y=k[xx].y+k[yy].y;

因为买云朵是要按照搭配一起买的,在这里就把与祖宗一样的价格和价值合在一起。

接下来就是先判断有多少个大物件,这里使用for循环,代码如下:

for(int i=1;i<=n;i++)
        if(fa[i]==i)
        {
            q[d]=k[i].x;
			r[d]=k[i].y;
            d++;
        }

这里用两个不同的数组分别记录与祖宗一样的价格和价值。

最后就是背包的动态规划,代码如下:

for(int i=1;i<=d;i++)
	{
		for(int j=w;j>=q[i];j--)
		dp[j]=max(dp[j],dp[j-q[i]]+r[i]);
	}
	cout<<dp[w];

因为结果是输出最大价值所以这里输出dp[w]

总代码如下:

#include <iostream>
using namespace std;
int n,m,w,d=0;int i,j;
int fa[10005];
int a,b,dp[10005];
int r[10005],q[10005];
struct node
{
    int x,y;
}k[10005];
int fun2(int x)
{
    if(fa[x]==x)
        return x;
    else fa[x]=fun2(fa[x]);
        return fa[x];
}
void fun1(int x,int y)
{
    int xx=fun2(x);
    int yy=fun2(y);
    if(xx!=yy)
    {
        k[xx].x=k[xx].x+k[yy].x;
        k[xx].y=k[xx].y+k[yy].y;
        fa[yy]=xx;
    }
}
int main()
{
    cin>>n>>m>>w;
    for(int i=1;i<=n;i++)
        cin>>k[i].x>>k[i].y;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=m;i++)
       {
           cin>>a>>b;
           fun1(a,b);
       }
    for(int i=1;i<=n;i++)
        if(fa[i]==i)
        {
            q[d]=k[i].x;
			r[d]=k[i].y;
            d++;
        }
    for(int i=1;i<=d;i++)
	{
		for(int j=w;j>=q[i];j--)
		dp[j]=max(dp[j],dp[j-q[i]]+r[i]);
	}
	cout<<dp[w];
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜杨杨349

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值