分组背包+二分图染色 (bitset+滚动数组优化)

六眼飞鱼酱① 提交于 2019-11-30 03:03:25

题目链接

题意:给你n种物品,有m种限制条件,然后输入n种物品的价值,m种限制条件,表示第i个物品不能与第j个物品分成一组,求把物品分成两组后,价值差最小,输出其中最大的价值。

思路:对于每一个限制条件,都可以看成一棵树,我们对这棵树染色,分成两组,然后把每一组都取上,输出答案。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
vector<int>G[205];
int a[205],c[205],val[3];
bitset<maxn> d[2];
void dfs(int u)  //染色
{
    val[c[u]]+=a[u];
    for(auto v : G[u])
    {
        if(!c[v])
        {
            c[v]=3-c[u];
            dfs(v);
        }
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        d[0].reset(); //把 bitset 置0;
        int n,m,sum=0;
        cin>>n>>m;
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            G[i].clear();
            a[i]/=100;  //题目数据说是整百的
            sum+=a[i];
        }
        for(int i=1;i<=m;i++)
        {
            int u,v;
            cin>>u>>v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int cur=0;
        d[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            val[1]=val[2]=0; //对一个二分图染色
            if(!c[i])
            {
                c[i]=1;
                dfs(i);    
                cur^=1;  // 滚动数组,因为当前状态只由前一个状态转移
                d[cur]=d[!cur];    
                d[cur]|=(d[!cur]<<val[1]);  
                d[cur]|=(d[!cur]<<val[2]);
            }
        }
        int ans;
        for(int i=sum/2;i>0;i--)
        {
            if(d[cur][i])
            {
                ans=sum-i;   
                cout<<ans*100<<'\n';
                break;
            }
        }
    }
}

 

tips:举例:假设你申明一个bitset<50>d,d[0]=1,d[1]=0,d[2]=1,d[3]=1; 那么d<<1,那么变成的d[0]=0,d[1]=1,d[2]=0,d[3]=1,d[4]=1;

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!