不会dp和并查集我来水个题
搭配购买
Description
Joe觉得云朵很美,决定去山上的商店买一些云朵。商店里有n朵云,云朵被编号为1,2,…,n,并且每朵云都有一个价值。但是商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这朵云有搭配的云都要买。
但是Joe的钱有限,所以他希望买的价值越多越好。
Input
第1行n,m,w,表示n朵云,m个搭配,Joe有w的钱。
第2∼n+1行,每行ci,di表示i朵云的价钱和价值。
第n+2∼n+1+m行,每行ui,vi,表示买ui就必须买vi,同理,如果买vi就必须买ui。
Output
一行,表示可以获得的最大价值。
Samples
Input
5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2
Output
1
Hint
【数据范围】
30%的数据保证:n≤100
50%的数据保证:n≤1,000;m≤100;w≤1,000
100%的数据保证:n≤10,000;0≤m≤5000;w≤10,000
思路:把所有在一组的物品打包后,看做一个物品,然后0 1背包即可。
这里打包的方法是并查集,让同一组的物品连起来后要跑一遍find函数,把父结点统一成同一个祖先结点。
Code:
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int N = 1e4+10;
const int inf = 0x3f3f3f;
int n,m,w;
int c[N],d[N],vis[N];
int p[N];
int dp[N],c2[N],d2[N];
int find(int x) {
if(x==p[x]) return x;
return p[x] = find(p[x]);
}
int main() {
cin>>n>>m>>w;
for(int i=1; i<=n; i++) {
scanf("%d%d",&c[i],&d[i]);
p[i] = i;
}
for(int i=1; i<=m; i++) {
int u,v;
scanf("%d%d",&u,&v);
p[find(u)] = find(v);
}
for(int i=1;i<=n;i++) find(i);
int k=0;
for(int i=1; i<=n; i++) {
if(!vis[i]) {
++k;
//cout<<p[i]<<"*"<<endl;
for(int j=1; j<=n; j++) {
if(p[j]==p[i]&&!vis[j]) {
vis[j]=1;
c2[k]+=c[j];
d2[k]+=d[j];
}
}
}
}
//cout<<k<<endl;
for(int i=1; i<=k; i++) {
for(int j=w; j>=c2[i]; j--) {
dp[j] = max(dp[j],dp[j-c2[i]]+d2[i]);
}
}
cout<<dp[w];
return 0;
}
明天要补英语啦,好像还得写什么有关寒假生活的的作文。
我我我…我TMD。