CodeForces

来源:互联网 发布:json socket java 编辑:程序博客网 时间:2024/06/06 00:01

CodeForces - 742D  Arpa's weak amphitheater and Mehrdad's valuable Hoses


   题意:n个人通过朋友关系分为若干组,每个人都有重量和美丽值,选取人在舞台承重量为W上跳舞,在不超过W的情况下求出最大美丽值,在每一个组里,要么挑选一个人去跳舞,要么挑选所有人都去跳舞,要么都不挑选

   思路:分组背包模板题,分组背包算法如下(摘自背包九讲)
   

    有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

算法

     这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:

f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于第k组}

使用一维数组的伪代码如下:

for 所有的组k

    for v=V..0

        for 所有的i属于组k

            f[v]=max{f[v],f[v-c[i]]+w[i]}

注意这里的三层循环的顺序,甚至在本文的beta版中我自己都写错了。“for v=V..0”这一层循环必须在“for 所有的i属于组k”之外。这样才能保证每一组内的物品最多只有一个会被添加到背包中。

另外,显然可以对每组内的物品应用P02中“一个简单有效的优化”。

小结

分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。不少背包问题的变形都可以转化为分组的背包问题(例如P07),由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题

利用并查集求出总共用多少组,再把每一组的所有人重量之和,美丽值之和当作一个' 泛化物品 '添加到这组里

#include<stdio.h>#include<algorithm>using namespace std;typedef long long ll;int f[1001],w[1001],b[1001];int len[1001]; ll dp[100005];struct hose{int w;ll b;}h[1001][1001]; int find(int x){if(x==f[x]) return x;else{f[x]=find(f[x]);return f[x];}}void merge(int x,int y){int fx=find(x),fy=find(y);if(fx!=fy) f[fy]=fx;}int main(void){int n,m,V;int x,y;int k=0,kcnt;ll sumw,sumb;scanf("%d%d%d",&n,&m,&V);for(int i=1;i<=n;i++){    scanf("%d",&w[i]);    f[i]=i;}for(int i=1;i<=n;i++)    scanf("%d",&b[i]);for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);merge(x,y);    }    for(int i=1;i<=n;i++){if(f[i]==i){          //找到新的一组 sumw=0,sumb=0;    //泛化物品,在这一组里所有人的重量之和,美丽值之和 k++;        //组数加一 kcnt=1;     //每一组有多少人 h[k][kcnt].w=w[i]; h[k][kcnt].b=b[i];sumw+=w[i],sumb+=b[i];}for(int j=1;j<=n;j++) {if(j!=i&&find(j)==i){kcnt++;h[k][kcnt].w=w[j];h[k][kcnt].b=b[j];sumw+=w[j],sumb+=b[j];}}//最后把泛化物品添加到这组里 kcnt++;h[k][kcnt].w=sumw;h[k][kcnt].b=sumb;len[k]=kcnt;}//分组背包模板 for(int i=1;i<=k;i++)    for(int j=V;j>=0;j--)    for(int p=1;p<=len[i];p++){    if(j>=h[i][p].w)       dp[j]=max(dp[j],dp[j-h[i][p].w]+h[i][p].b);    }printf("%lld\n",dp[V]);return 0;    }