洛谷P1455 搭配购买(tarjan+dp)

来源:互联网 发布:微信开发 未备案域名 编辑:程序博客网 时间:2024/05/21 17:00

搭配购买

题目描述

明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有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

输出格式:
一行,表示可以获得的最大价值。

分析:用tarjan缩点然后做一下01背包。

代码

#include <cstdio>#include <cstring>#include <stack>#define maxn 20000using namespace std;stack<int> s;int x[maxn],y[maxn],next[maxn],ls[maxn],c[maxn],d[maxn],c1[maxn],d1[maxn],dfn[maxn],low[maxn],f[maxn];int n,m,w,cnt=0,p=0;bool v[maxn];void tarjan(int i){    p++;    s.push(i);    v[i]=true;    dfn[i]=p;    low[i]=p;    for (int k=ls[i];k;k=next[k])    {        int j=y[k];        if (dfn[j]==0)        {            tarjan(j);            if (low[j]<low[i]) low[i]=low[j];        }        else         {            if (v[j]&&low[i]>dfn[j])                low[i]=dfn[j];        }    }    if (dfn[i]==low[i])    {        cnt++;        int j=0;        do        {            j=s.top();            s.pop();            v[j]=false;            c1[cnt]+=c[j];            d1[cnt]+=d[j];        }        while (i!=j);    }}int max(int i,int j){    if (i>j) return i;    return j;}int main(){    int xx=0,x1,y1;    scanf("%d%d%d",&n,&m,&w);    for (int i=1;i<=n;i++)        scanf("%d%d",&c[i],&d[i]);    for (int i=1;i<=m;i++)    {        scanf("%d%d",&x1,&y1);        xx++;        next[xx]=ls[x1];        ls[x1]=xx;        x[xx]=x1;        y[xx]=y1;        xx++;        next[xx]=ls[y1];        ls[y1]=xx;        x[xx]=y1;        y[xx]=x1;    }    for (int i=1;i<=n;i++)        if (dfn[i]==0) tarjan(i);    for (int i=1;i<=cnt;i++)        for (int j=w;j>=c1[i];j--)            f[j]=max(f[j],f[j-c1[i]]+d1[i]);    printf("%d",f[w]);}
原创粉丝点击