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