Jurassic Remains LA 2965(中途相遇法)

【中途相遇法】:

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

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

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

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<string.h>
#define mod 256
#define maxn 10005
using namespace std;

int A[30];
char s[30];
map<int,int> table;
int bitcount(int x){return x==0? 0 : bitcount(x/2)+(x&1);}

int main(){
    int n;
    while(cin>>n&&n)
    {
        for(int i=0;i<n;i++)
        {
            cin>>s;
            A[i]=0;
            for(int j=0;s[j]!='\0';j++)
            {
                A[i]^=(1<<(s[j]-'A'));
            }
        }
        table.clear();
        int n1=n/2,n2=n-n1;
        for(int i=0;i<1<<n1;i++)
        {
            int x=0;
            for(int j=0;j<n1;j++)
            {
                if(i&(1<<j))  x^=A[j];
            }
            if(!table.count(x) || bitcount(table[x])<bitcount(i)) table[x]=i;
        }
        int ans=0;
        for(int i=0;i<1<<n2;i++)
        {
            int x=0;
            for(int j=0;j<n2;j++)
                if(i&(1<<j))  x^=A[j+n1];
            if(table.count(x)&&bitcount(ans)<bitcount(i)+bitcount(table[x]))
                ans=(i<<n1)^table[x];
        }
        printf("%d\n",bitcount(ans));
        for(int i=0;i<n;i++)
            if(ans&(1<<i))    printf("%d ",i+1);
        puts("");
    }
    return 0;
    }

猜你喜欢

转载自blog.csdn.net/sadsummerholiday/article/details/82953325
LA