洛谷——P1455 搭配购买
题目描述
明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n朵云,云朵已经被老板编号为1,2,3,……,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。
输入输出格式
输入格式:
第1行n,m,w,表示n朵云,m个搭配和你现有的钱的数目
第2行至n+1行,每行ci,di表示i朵云的价钱和价值
第n+2至n+1+m ,每行ui,vi表示买ui就必须买vi,同理,如果买vi就必须买ui
输出格式:
一行,表示可以获得的最大价值
输入输出样例
输入样例#1:
5 3 103 103 103 105 10010 11 33 24 2
输出样例#1:
1
说明
30%的数据满足:n<=100
50%的数据满足:n<=1000;m<=100;w<=1000;
100%的数据满足:n<=10000;0<=m<=5000;w<=10000.
思路:
tarjan缩点后跑01背包。。
代码:
#include#include #include #include #include #define N 10001using namespace std;int x,y,w,n,m,t,tat,sum,top,time;int v[N],c[N],f[N],head[N],col[N];int cc[N],vv[N],stack[N],dfn[N],low[N];bool vis[N];struct Edge{ int from,next,to; }edge[N];int add(int x,int y){ tat++; edge[tat].to=y; edge[tat].next=head[x]; head[x]=tat;}int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return f*x;}int tarjan(int now){ dfn[now]=low[now]=++time; stack[++top]=now; vis[now]=true; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(vis[t]) low[now]=min(low[now],dfn[t]); else if(!dfn[t])tarjan(t),low[now]=min(low[now],low[t]); } if(low[now]==dfn[now]) { sum++;col[now]=sum; vv[sum]+=v[now]; cc[sum]+=c[now]; for(;stack[top]!=now;top--) { cc[sum]+=c[stack[top]]; vv[sum]+=v[stack[top]]; col[stack[top]]=sum; vis[stack[top]]=false; } vis[now]=false; }}int main(){ n=read(),m=read(),w=read(); for(int i=1;i<=n;i++) v[i]=read(),c[i]=read();//v为价格,c为价值 for(int i=1;i<=m;i++) x=read(),y=read(),add(x,y),add(y,x);//建双向边 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);//tarjan for(int i=1;i<=sum;i++)//01背包求用最少的钱获得最大的价值 for(int j=w;j>=vv[i];j--) f[j]=max(f[j],f[j-vv[i]]+cc[i]); //printf("%d\n",sum); printf("%d",f[w]); return 0;}