「Codeforces」742D Arpa's weak amphitheater and Mehrdad's valuable Hoses (背包、并查集)

题意:原题在这

 

有n个人(1<=n<=1000)。每个人有一个重量wi(1<=wi<=1000)和一个魅力值bi(1<=bi<=10^6)。 n个人之间有m(1<=m<=min(n*(n-1)/2, 10^5))个关系。第i个关系由两个数字xi和yi组成,表示第xi个人和第yi个人是朋友,朋友关系是双向的。 已知若a和b是朋友,b和c是朋友,则a和c是朋友。 现在Mehrdad要邀请一些人来到派对,使这些人的重量总和不超过wi(1<=wi<=1000),且魅力值总和尽量大。同一个朋友圈里的人,只能邀请其中的一个人,或者全部人,或者一个人也不邀请。

输入格式: 第一行,三个整数n,m,w 第二行,n个整数w1,w2,...,wn 第三行,n个整数b1,b2,...,bn 接下来m行,每行表示一个关系,第i行有两个整数xi和yi。每一组朋友关系都是不同的。

输出格式: 一行,表示最大的魅力值总和。

 

做法:

1. 用并查集管理集合,开vector数组方便对集合进行遍历

2. 把集合看成一件物品,因为要么从集合中取一个元素,要么取整个集合,那么就对这个集合中的每件物品背一次,然后对这件物品背一次。

3.dp[i]表示当前重量为i的最大颜值,输出dp[maxweight]即可。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include<vector>
#define inf 9999999999
using namespace std;
int n,m,weight;
vector<int> vec[1005];
int by[1005], wt[1005], fa[1005];
long long dp[1005];

int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

void unite(int x,int y)
{
    fa[find(x)]=fa[find(y)];
}

int main()
{
    cin>>n>>m>>weight;
    for(int i=1;i<=n;i++) cin>>wt[i];
    for(int i=1;i<=n;i++) cin>>by[i];
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=0;i<m;i++)
    {
        int x;int y;
        cin>>x>>y;
        if(find(x)!=find(y)) unite(x, y);
    }

    for(int i=1;i<=n;i++) vec[find(i)].push_back(i);
    
    for(int i=1;i<=n;i++)
    {
        if(fa[i]==i)
        {
            for(int j=weight;j>=0;j--)
            {
                int sumwt=0,sumby=0;
                for(int k=0;k<vec[i].size();k++)
                {
                    sumby+=by[vec[i][k]];
                    sumwt+=wt[vec[i][k]];
                    if(j>=wt[vec[i][k]]) dp[j]=max(dp[j],dp[j-by[vec[i][k]]]+by[vec[i][k]]);
                }
                if(j>=sumwt) dp[j]=max(dp[j],dp[j-sumwt]+sumby);
            }
        }
    }
    cout<<dp[weight]<<endl;
    return 0;
}

 

posted @ 2018-09-09 18:45  LocaEtric  阅读(217)  评论(0编辑  收藏  举报