dp训练第20题 csu1326: The contest 分组背包 并查集

版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/79951783

给定n个物品和一个容量为v的背包,还有m对连锁物品.每个物品都有一个体积volume[i]和价值value[i].如果两个物品是连锁的,那么它们不能同时放入背包中.注意连锁是具有传递性的.

用并查集将连锁物品分组,然后做分组背包即可.慎重写题.

并查集现在写的比较熟练了

int getfa(int p)
{
    return save[p].fa==p?p:(save[p].fa=getfa(save[p].fa));
}

while(line--)
{
    int ta=getfa(read()),tb=getfa(read());
    save[tb].fa=save[ta].fa=min(ta,tb);
}
for(int i=1;i<=n;i++) getfa(i);

注意最后一句一定是必要的.

分组背包,这道题中没有显式地进行分组,只是先按组别进行了排序,将组别相同的放在一块.

    sort(save+1,save+1+n);
    for(int k=1;k<=n;k++)
    {
        int i=k;
        for(int j=v;j>=0;j--)
        for(i=k;i<=n;i++)
        {
            if(j>=save[i].volume)
                dp[j]=max(dp[j],dp[j-save[i].volume]+save[i].value);
            if(save[i+1].fa!=save[i].fa) break;
        }
        k=i;
    }
    printf("%d\n",dp[v] );

分组遍历使用的是向前探查,如果前方物品和当前物品组别不一样则break.
注意不用设置n+1的物品,因为i++超过n后也会退出.(这个方法感觉复杂度有些高)
多写几下,熟悉这个过程.

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页