LA 2965 - Jurassic Remains 中途相遇法
題意:
給定n個字符串,求最多選幾個並保證所有字母出現偶數次
n最大為24,直接枚舉2^24,對於18s的實現貌似也是可以接受的,但必然不好。想了很久降複雜度的方法都沒想到好的,用中途相遇發隻能降到(2^n/2)log(n),對於n很大還是無力
中途相遇法指把原問題化為兩個獨立的子問題,一半通過枚舉暴力完成,另一半枚舉時利用map等結構查詢前一半的結果,合並得出最終結果
/*
author:jxy
lang:C/C++
university:China,Xidian University
**If you need to reprint,please indicate the source**
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
int count_one(int x)//分治計數
{
x=(x&0x55555555)+(x>>1&0x55555555);
x=(x&0x33333333)+(x>>2&0x33333333);
x=(x&0x0F0F0F0F)+(x>>4&0x0F0F0F0F);
x=(x&0x00FF00FF)+(x>>8&0x00FF00FF);
x=(x&0x0000FFFF)+(x>>16&0x0000FFFF);
return x;
}
int org[26],n;
map<int,int> table;
int main()
{
while(~scanf("%d",&n))
{
char s[50];
int i,j,len;
for(i=0;i<n;i++)
{
scanf("%s",s);
len=strlen(s);
org[i]=0;
for(j=0;j<len;j++)
{
org[i]^=1<<(s[j]-'A');
}
}
int n1=n>>1,n2=n-n1,tmp,t,now;
tmp=1<<n1;now=0;
table.clear();
for(i=0;i<tmp;i++)//枚舉一半
{
t=i;j=0;
now=0;
while(t)
{
if(t&1)now^=org[j];
j++; t>>=1;
}
if(count_one(table[now])<count_one(i))table[now]=i;//記錄最大值
}
tmp=1<<n2;
int ans=0;
for(i=0;i<tmp;i++)
{
t=i;j=0;
now=0;
while(t)
{
if(t&1)now^=org[j+n1];
j++; t>>=1;
}
if(table[now]!=0&&count_one(ans)<(count_one((i<<n1)^table[now])))//題目沒說多組情況,用<可以過
{
ans=(i<<n1)^table[now];
}
}
printf("%d\n",count_one(ans));
for(i=0;ans;i++,ans>>=1)
if(ans&1) printf("%d%c",i+1,ans>>1?' ':'\n');
}
}
最後更新:2017-04-03 12:54:44