T1 彩虹
题目
【题目描述】
Mr.Raju和他的一个大家庭外出度假,他们想要乘着彩虹欣赏周围的景色,但是这样最会有一些问题。
在他们家族中,如果一个人想要骑上彩虹,那么他喜欢的所有人和喜欢他的所有人都必须一同骑上彩虹。如果一个人没有喜欢的人,也没有人喜欢他,那么他也可以乘上彩虹。
你被请来解决这个难题,我们会提供给你家族所有成员的体重,以及每个人喜欢的人的列表,同样给出的还有彩虹能承受的总重量,你需要计算出在以上条件下彩虹所能承载的最多人数。
为了方便描述,所有的家庭成员都被标号,从1到n。
【输入格式】
有多组数据,每组数据之间有一空行。
对于每一组数据,第一行为整数n(1≤n≤1000)和c(0≤c≤1000),n表示家庭成员的总人数,c表示彩虹的承载量。
第二行为n个数为1到n个家庭成员的体重(体重是1000以内的正整数)。
接下来n行,每行第一个数k[i]表示第i个人有多少喜欢的人,接下来k[i]个整数为他喜欢的人的编号。
当n=0,c=0是表示数据结束。保证数据组数不超过3。
【输出格式】
对于每一组数据,输出可以同时骑彩虹的最大人数。(输出的每个答案之间不要空行)。
【输入样例】
5 200 50 50 50 50 50 1 2 1 3 0 1 5 1 4 3 200 100 100 100 1 2 1 3 1 1 0 0
【输出样例】
3 0
【数据规模】
对于20%的数据:n≤8;
对于100%的数据:n,c≤1000。
解析
先用并查集将每个人与其喜欢的人合并起来,计算他们的总重量与总人数。
再跑一遍01背包即可。
Code
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> using namespace std; int read() { int num=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); } return num*w; } const int N=1010; int n,C,a[N],b[N],c[N],fa[N],f[N],maxn; int get(int x) { if(fa[x]==x) return x; return fa[x]=get(fa[x]); } int main() { //freopen("rainbow.in","r",stdin); //freopen("rainbow.out","w",stdout); while(1) { n=read(),C=read(),maxn=0; if(n==0&&C==0) break; memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) a[i]=read(),b[i]=0,c[i]=0,fa[i]=i; for(int i=1;i<=n;i++) { int k=read(); for(int j=1;j<=k;j++) { int x=read(); fa[get(i)]=get(x); } } for(int i=1;i<=n;i++) { int temp=get(i); b[temp]+=a[i],c[temp]++; } for(int i=1;i<=n;i++) if(b[i]!=0) for(int j=C;j>=b[i];j--) f[j]=max(f[j],f[j-b[i]]+c[i]); for(int i=0;i<=C;i++) maxn=max(maxn,f[i]); cout<<maxn<<endl; } return 0; }