1. 程式人生 > >P1455 搭配購買

P1455 搭配購買

就是 pri 最大 一朵 -o turn class 自己的 urn

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 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2

輸出樣例#1: 復制
1

說明

30%的數據滿足:n<=100

50%的數據滿足:n<=1000;m<=100;w<=1000;

100%的數據滿足:n<=10000;0<=m<=5000;w<=10000.

01背包問題,不過有依賴。

我們不妨把所有有依賴的分成新的組別,每個組別的價值為組成雲的價值和,價錢也是一樣。

那麽對於這些組別進行01背包問題就行……

1、並查集,每個集合代表的價值為該集合價值和,價錢亦然。

2、tarjan縮點,不多說,看代碼就行。

AC代碼如下(我用的是方法2)

#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;
const int N=10000+5;
stack<int>s;
struct p{
    int to,nxt;
}e[N*3];
int fir[N],dfn[N],low[N],nd[N],num,t,tot,val[N],x,y,z,n,m,ww,w[N],v[N],f[N];
bool in[N]; void add(int from,int to) { tot++; e[tot].to=to; e[tot].nxt=fir[from]; fir[from]=tot; return; } void dfs(int x) { in[x]=1; s.push(x); dfn[x]=low[x]=++t; for(int i=fir[x];i;i=e[i].nxt) if(!dfn[e[i].to]) dfs(e[i].to),low[x]=min(low[x],low[e[i].to]); else if(in[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); if(dfn[x]==low[x]) { num++; v[num]=val[x]; w[num]=nd[x]; in[x]=0; while(s.top()!=x) v[num]+=val[s.top()],w[num]+=nd[s.top()],in[s.top()]=0,s.pop(); s.pop(); } return; } int main() { scanf("%d%d%d",&n,&m,&ww); for(int i=1;i<=n;i++) scanf("%d%d",&nd[i],&val[i]); for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); for(int i=1;i<=num;i++) for(int j=ww;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]); printf("%d",f[ww]); return 0; }

P1455 搭配購買