zoukankan      html  css  js  c++  java
  • LA2965侏罗纪

    LA2965侏罗纪

    http://122.207.68.93:9090/csuacmtrain/problem/viewProblem.action?id=3148

    【题目描述】:给定n个大写字母组成的连续字符串,(n<=24),选取其中的m个组合,使相同的大写字母的出现次数之和为偶数。目标是让这个m最大。

    【算法分析】:

    Ps:这道题看着比较简单,但是编码有难度。

    【中途相遇法】:

    首先,如果将每种状态用位表示,就是2^24种状态,1表示奇数个,0表示偶数个。利用异或运算的特殊性,模二加,奇数与奇数异或是偶数。所以我们的目的是找出m个数异或,使他们的结果为0。到这里为止,已经保证了编码的简便性。

    但是,复杂度任然是难以支撑。朴素的算法为2^24(==16000000)种情况,超时。书中提供“中途相遇法”,将考虑的情况分为两半,一边是2^12(==4096)种,因为两个数异或,只有完全相等,才能为0。所以生成前半部分的“选取个数”(我们只关注这个)和“异或结果”的匹配的集合map。后半部分,每次生成一个新的匹配的时候,查找用nlog2n)的复杂度即可。精髓在于“打表+查找”?

    【综合复杂度】:2* 2^24+24*log2(24)约等于10000

    #include<iostream>

    #include<stdio.h>

    #include<string.h>

    #include<algorithm>

    #include<stdlib.h>

    #include<math.h>

    #include<queue>

    #include<vector>

    #include<set>

    #include<map>

    #define MAXN 100+5

    #define MAXM 100+5

    #define oo 1e9

    #define eps 0.001

    #define PI acos(-1.0)//这个精确度高一些

    #define REP1(i,n) for(int i=0;i<=(n);i++)

    #define REP2(i,n) for(int i=1;i<=(n);i++)

    #define DREP2(i,n) for(int i=(n);i>=1;i--)

    #define LL long long

    using namespace std;

     

    int nums[MAXN];//表示统计的异或的结果

    int n;

    int p1,p2;

    map<int,int> Map;

    //int getbits(int x)

    //{

    //    int ans=0;

    //    while(x>0)

    //    {

    //        ans+=(1&x);

    //        x>>1;

    //    }

    //    return ans;

    //}

     

    int getbits(int x)//这个统计位数的函数值得学习

    {

        return x==0?0:getbits(x/2)+(x&1);

    }

    void readin()

    {

        memset(nums,0,sizeof(nums));

        char s[10005];

        for(int i=0;i<n;i++)

        {

            cin>>s;

            int len=strlen(s);

            for(int j=0;j<len;j++)

            nums[i]=nums[i]^(1<<(s[j]-'A'));//存储的是za的结果

        }

        return ;

    }

     

    void makeMap()

    {

        Map.clear();

        int p=n/2;

        for(int i=0;i<(1<<p);i++)//状态压缩,枚举每种组合情况

        {

    //        cout<<"i="<<i<<endl;

            int x=0;//存储每种组合异或的结果,注意初始化为00和任何数异或等于原数

            for(int j=0;j<p;j++) {if (i&(1<<j)) x=x^nums[j];}//读取每位上的数字,注意nums1开始存储

            if (!Map.count(x))Map[x]=i;//查找关键字//注意i中既包含位数又包含选择信息

            else if (getbits(Map[x])<getbits(i)) Map[x]=i;

        }

        return;

    }

    void getans()

    {

        int ans=0;

        int p=n-n/2;//枚举后p,状态压缩比搜索好写啊

     

        for(int i=0;i<(1<<p);i++)

        {

            int x=0;

            for(int j=0;j<p;j++)

                if (i&(1<<j)) x=x^nums[j+n/2];//同上

            if (Map.count(x))//注意:我们的目标是异或结果为0,即两个x相等

            {

                int k1=getbits(i),k2=getbits(Map[x]),m=getbits(ans);

                if (m<k1+k2)

                {

    //                ans=(Map[x]<<(n/2))^i;//注意好移动步数

                      ans=(i<<(n/2))^Map[x];

                }

     

            }

        }

        cout<<getbits(ans)<<endl;

        if (ans>0)

        {

            int cnt=0,A[105];

            for(int i=0;i<n;i++) if (ans &(1<<i)) A[cnt++]=i+1;

            for(int i=0;i<cnt-1;i++) cout<<A[i]<<" ";

            cout<<A[cnt-1]<<endl;

        }

     

        cout<<endl;

        return;

    }

     int main(){

        while(cin>>n && n)

        {

        readin();

        makeMap();//构建前1--n/2组合异或的MAP,用状态压缩实现

        getans();

        }

        return 0;

    }

    【关键词】:位运算,中途相遇法,建模

  • 相关阅读:
    《刀塔传奇》
    SSH端口转发
    objective-c与c++的差异
    mysql 远程连接速度慢的解决方案
    maven
    automapper 自动映射 集成asp.net Core2.1
    swagger 集成asp.net Core2.1
    asp.net Core 跨域配置
    处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
    SharedPreferences
  • 原文地址:https://www.cnblogs.com/little-w/p/3521433.html
Copyright © 2011-2022 走看看