P1455
搭配购买
题目描述
明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有 \(n\) 朵云,云朵已经被老板编号为 \(1,2,3,...,n\),并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。
输入格式
第一行输入三个整数,\(n,m,w\),表示有 \(n\) 朵云,\(m\) 个搭配和你现有的钱的数目。
第二行至 \(n+1\) 行,每行有两个整数, \(c_i,d_i\),表示第 \(i\) 朵云的价钱和价值。
第 \(n+2\) 至 \(n+1+m\) 行 ,每行有两个整数 \(u_i,v_i\)。表示买第 \(u_i\) 朵云就必须买第 \(v_i\) 朵云,同理,如果买第 \(v_i\) 朵就必须买第 \(u_i\) 朵。
输出格式
一行,表示可以获得的最大价值。
样例 #1
样例输入 #1
5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2
样例输出 #1
1
提示
- 对于 \(30\%\) 的数据,满足 \(1 \le n \le 100\);
- 对于 \(50\%\) 的数据,满足 \(1 \le n, w \le 10^3\),\(1 \le m \le 100\);
- 对于 \(100\%\) 的数据,满足 \(1 \le n, w \le 10^4\),\(0 \le m \le 5 \times 10^3\)。
并查集 or 缩点 + 0-1 Pack Dp
在练习缩点所以用tarjan做
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n,m,w;
struct Graph{
int from,to,nxt;
}edge[N<<1];
int head[N],cnt;
inline void add(int u,int v)
{
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
int low[N],dfn[N],times,stack_[N],c[N],d[N],c_[N],d_[N],vis[N],pt,tot,belong[N];
void tarjan(int x)
{
dfn[x]=low[x]=++times;
stack_[++pt]=x;
vis[x]=1;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[x]=min(low[x],low[v]);
}
else{
if(vis[v])
low[x]=min(low[x],dfn[v]);
}
}
if(dfn[x]==low[x])
{
tot++;
while(1)
{
belong[stack_[pt]]=tot;
vis[stack_[pt]]=0;
c_[tot]+=c[stack_[pt]];
d_[tot]+=d[stack_[pt]];
pt--;
if(stack_[pt+1]==x)break;
}
}
}
int f[N];//Dp
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>w;
for(int i=1;i<=n;i++)cin>>c[i]>>d[i];
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=tot;i++)//0-1 pack
for(int j=w;j>=c_[i];j--)// reverse -->
f[j]=max(f[j],f[j-c_[i]]+d_[i]);
cout<<f[w]<<"\n";
return 0;
}