cf 1105 e 位操作 状压dp(记忆化搜索)

链接:https://codeforces.com/contest/1105/problem/E

题意:有m个人(<=40),申请访问主页,如果每次主页是它的名字,他会很开心。n次操作,每次当为1的时候可以设置主页。

思路:这样可以看做一个图,把每个人看做一个点,那么在每一次访问主页有冲突的,那么这些点是不能共同存在的。

  在最后找一个最大的独立集。

做法 : 位操作+记忆化搜索

开始处理 g[x]:  用二进制表示他与其他点的关系,1代表可以共存,0代表不可以

之后从(1<<m )-1开始记忆化搜索,有两种情况,

(1)对这个J保留,则要&g[j] 结果+1继续搜下去。

(2)不保留,则 &(1<<j)

 

细节:位操作是个很细腻的东西啊。。以及记忆化搜索的时候,因为

数组开的不能太大,值开到了1<<20,那么开始的时候就尽量消去权重大的1

#include<bits/stdc++.h>
using namespace std;

#define bug printf("??");
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(v) v.begin(),v.end()
#define mem(a) memset(a,0,sizeof(a))

const int N = 2e5+4;
const ll mod =1e9+7;
const int INF = 1e9+4;
const double eps = 1e-7;
ll dp[1<<20];
vector<ll>V;
ll g[55];

int dfs(ll x){
   int res=  x>= (1<<20)?0:dp[x];
   if(res==0 && x){
        //这样是把最前面的1去掉  因为记忆化只在1到1<<20
        //所以优先去掉 权重大的1
        int j=63-__builtin_clzll(x);
        //  int j = __builtin_ctzll(x)  这样是把最尾的1去掉
        res = max( dfs( x^ (1ll<<j)) ,dfs( x& (g[j]))+1 );
   }
   if(x<(1ll<<20)) dp[x] =res;
   return res;
}

int main(){
    int n,m;
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin>>n>>m;
    map<string ,int >M;
    string s;
    int cnt= 0 ;int op;
    for(int i=1;i<=n;++i){
        //scanf("%d",&op);
        cin>>op;
        if(op==1) V.push_back(0);
        else {
            cin>>s;
            if(M.find(s)==M.end())
                M.insert({s, M.size()});
            //这里用二进制保存所有的点 为了之后处理
            V.back() |= (1ll<<M[s]);
        }
    }


    for(int i=0;i<m;++i) g[i]= (1ll<<m) -1;
    for(int i=0;i<m;++i) g[i] &= ~(1ll<<i);
    for(int i=0;i<V.size();++i){
        for(int a=0;a<m;++a){
            for(int b=0;b<m;++b){
                if(  ((V[i]>>a)&1) && ((V[i]>>b)&1) ){
                    g[a]&= ~(1ll<<b);
                }
            }
        }
    }
    /*for(ll vi : V)
        for(int i=0; i<m; ++i)
            for(int j=0; j<m; ++j)
                if(vi>>i&1&&vi>>j&1)
                    g[i]|=1ll<<j;
    for(int i=0; i<m; ++i)
        g[i]=~g[i];*/
    int ans = dfs(  (1ll<<m )-1);
    cout<<ans<<endl;
    return 0;
}

 

posted on 2019-01-21 18:41  Helpp  阅读(306)  评论(0编辑  收藏  举报

导航