POJ 1903 - Jurassic Remains 中途相遇法(枚举)
神奇的枚举题~~~超级好的思路!
题意重现...从n(n<=24)个字符串中选取最多的串使得他们中每个字母出现的次数都是偶数次....
由此可见..个数都是浮云..奇偶才是本质...对于每个字母..有偶数个..为0..有奇数个为1..那么26个英文字母的情况总数为2^26..
题意抽象..从n(n<=24)个二进制数中(位<=26)选取最多的个数...使它们异或后为0...
如果暴力枚举...2^24=10^7...加些剪枝应该能过..毕竟给了10s....
此题的超级优化....把24个串分成前后两半...前面的做暴力枚举..并把结果丢到集合里去...2^12....后面的也暴力枚举..并且每次的结果去集合里看有无出现过相同的..如果有那么异或后为0..就是符合题目要求的..找到个数最多的!...这样一优化...前后两个2^12+2^12..瞬间时间复杂度开方了!给跪....
Program:
#include<iostream> #include<stdio.h> #include<string.h> #include<cmath> #include<map> #include<algorithm> #define ll long long using namespace std; struct node { int w[25],num; }ans; char s[25][105]; int n; map<int,node> mymap; void dfs1(int i,int x,node h) { int l,j; if (mymap.find(x)==mymap.end()) mymap[x]=h; if (mymap[x].num<h.num) mymap[x]=h; if (i>n/2) return; dfs1(i+1,x,h); l=strlen(s[i]); for (j=0;j<l;j++) x^=1<<(int)(s[i][j]-'A'); h.w[++h.num]=i; dfs1(i+1,x,h); return; } void dfs2(int i,int x,node h) { int l,j; if (mymap.find(x)!=mymap.end() && mymap[x].num+h.num>ans.num) { ans=mymap[x]; for (j=1;j<=h.num;j++) ans.w[++ans.num]=h.w[j]; } if (i>n) return; dfs2(i+1,x,h); l=strlen(s[i]); for (j=0;j<l;j++) x^=1<<(int)(s[i][j]-'A'); h.w[++h.num]=i; dfs2(i+1,x,h); return; } int main() { int i; node h; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%s",s[i]); h.num=0; mymap.clear(); dfs1(1,0,h); ans.num=0; dfs2(n/2+1,0,h); printf("%d\n",ans.num); for (i=1;i<=ans.num;i++) printf("%d ",ans.w[i]); return 0; }