有一些云朵商品,你需要如果商品有搭配关系,则你需要购买具有搭配关系的所有云朵;
已知你的初始财富以及各物品的价钱与价值,求出最大价值
思路
这题一开始写的(O(n^2m))的暴力,得分为40pt
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5, W=1e3+5;
int n,m,cap, fa[N], sz[N], f[W];
struct node {
int cost, val;
} A[N];
int find(int u) {
return fa[u]==u ? u : fa[u]=find(fa[u]);
}
void merge(int u, int v) {
int fu=find(u), fv=find(v);
if (sz[fu]>sz[fv]) {
fa[fv]=fu;
sz[fu]+=sz[fv];
} else {
fa[fu]=fv;
sz[fv]+=sz[fu];
}
}
bool isConn(int u, int v) {
return find(u)==find(v);
}
int buy(int u, int& cap) {
int tot_val=A[u].val;
for (int i=1; i<=n; i++) if (i!=u && isConn(i,u)) {
cap-=A[i].cost, tot_val+=A[i].val;
if (cap<0)
return -1;
}
return tot_val;
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n>>m>>cap;
for (int i=1; i<=n; i++) cin>>A[i].cost>>A[i].val, fa[i]=i, sz[i]=1;
for (int i=0; i<m; i++) {
int u,v; cin>>u>>v;
merge(u,v);
}
for (int i=1; i<=n; i++)
for (int j=cap; j>=A[i].cost; j--) {
int t=j-A[i].cost, v=buy(i,t);
if (v!=-1)
f[j]=max(f[j], f[t]+v);
}
cout<<f[cap];
return 0;
}
直接用一个连通块的根记录总的cost、val,让子节点的cost、val变为0,这样就省去了buy函数的O(n)的检查时间
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5, W=1e3+5;
int n,m,cap, fa[N], sz[N], f[W];
struct node {
int cost, val;
} A[N], B[N];
int find(int u) {
return fa[u]==u ? u : fa[u]=find(fa[u]);
}
void merge(int u, int v) {
int fu=find(u), fv=find(v);
if (sz[fu]>sz[fv]) {
fa[fv]=fu;
sz[fu]+=sz[fv];
} else {
fa[fu]=fv;
sz[fv]+=sz[fu];
}
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n>>m>>cap;
for (int i=1; i<=n; i++) cin>>A[i].cost>>A[i].val, fa[i]=i, sz[i]=1;
for (int i=0; i<m; i++) {
int u,v; cin>>u>>v;
merge(u,v);
}
for (int i=1; i<=n; i++) {
int fi=find(i);
B[fi].val+=A[i].val, B[fi].cost+=A[i].cost;
A[i].val=0, A[i].cost=0;
}
for (int i=1; i<=n; i++)
for (int j=cap; j>=B[i].cost; j--) {
f[j]=max(f[j], f[j-B[i].cost]+B[i].val);
}
cout<<f[cap];
return 0;
}