Meeting-in-the-Middle,又称“中途相遇法”。准确地说,它只是一种策略。

顺便说一下,这个算法真的很冷门!

结合这道题来讨论一下吧:LA 2965。ε(┬┬﹏┬┬)3

因为博主的英文实在是十分拙劣,所以只能给出题目大意:

题目大概是说,输入多组数据(组数未知 反正不多啦),每组给定一个$k<=24$,代表有k个字符串。

然后每组的后k行,依次输入这么多个字符串。

要求你选择尽量多的字符串,使得被选的字符串中的所有字母中,每种字母都出现偶数次。

输出选择字符串数,并从小到大输出被选字符串。

给组样例吧:

in

ABC

ABD
EG
GE
ABE
AC
BCD

out


      

这个题目,乍一看上去,博主就只想到了模拟。。。(博主蒟蒻一枚)。

事实上,仔细分析,我们会发现:

这个题目,和字母的个数实际上没多大关系,更多的是和字母出现次数的奇偶有关。

于是我们假设有这么一张表:(拿样例中k=6的那一组为例)

A B C D E F G H……
……
……
……
……
……
…… 

代表什么呢?显然这个表上的每一行都是一个26为的二进制数,而每一位对应一个字母,代表这个字母在此串中出现次数的奇或偶。

1代表的是奇,0代表的是偶。

仔细想想,我们是不是只要这么做:选择尽量多的串,使其异或值为0。

好。有了这张表,这就好办了。我们可以进行暴力穷举法$O(2^n)$。是不是还是很low?显然,这个时间复杂度过不了规模高达24的数据。

那么,我们怎么办呢?

这时候,我们开始讲到的MITM策略就可以派上用场了。

别看它的名字这么高级,其实思想主要是:

将待测数据(也就是那张表)分成两部分,枚举上表的所有子集的xor值,放入一个hash表或者map映射里。

然后枚举后半部分的数据所能得到的所有xor值,并每次都在hash表或者map映射里查找。

如果用map实现的话,总时间复杂度为$O(2^{(n/2)}logn)$,即$O(1.414^nlogn)$,比第一种方法好了很多。

这就是Meeting-in-the-Middle中途相遇法。

据刘汝佳神犇所述:密码学中的著名的中途相遇攻击(Meeting-in-the-Middle attack)就是基于这个原理。

最后贴上代码吧:

#include <bits/stdc++.h>
using namespace std; const int maxn=;
map <int,int> table; int bitcount(int x) {
return x==?:bitcount(x/)+(x&);
}//这个函数用来计算这个数在二进制下有多少个1 int main()
{
int n,A[maxn];
char s[];
while (scanf("%d",&n)==&&n) {//读入多组数据
for (int i=;i<n;i++) {
scanf("%s",s);//输入字符串
A[i]=;
for (int j=;s[j]!='\0';j++)
A[i]^=(<<(s[j]-'A'));//计算每一串的<=26位二进制值
}
table.clear();//清空table映射
int n1=n/,n2=n-n1;//将待测数据分成两部分 //接下来循环计算2^(n/2)个属于前半部分的子集
for (int i=;i<(<<n1);i++) {
int x=;
for (int j=;j<n1;j++)
if (i&(<<j)) x^=A[j];
if (!table.count(x)||bitcount(table[x])<bitcount(i))
table[x]=i;
}//取每个计算结果中的最大值 //最后处理后半部分
int ans=;
for (int i=;i<(<<n2);i++) {
int x=;
for (int j=;j<n2;j++)
if (i&(<<j)) x^=A[n1+j];
if (table.count(x)&&bitcount(ans)<bitcount(table[x])+bitcount(i))
ans=(i<<n1)^table[x];
}//每次计算前查找映射中是否出现过
printf("%d\n",bitcount(ans));
for (int i=;i<n;i++)
if (ans&(<<i)) printf("%d ",i+);
printf("\n");//输出部分
}
return ;
}

如果不用map也可以改成哈希(hash):

int insHash(int x)
{
int c=x%MOD;
for (int u=h[c];u;u=nexp[u])
if (val[u]==x) return u;
if (!gans)
nexp[p]=h[c],h[c]=p,val[p]=x,p++;
return -(p-);
}

然后听机房一位神犇说,这题用深搜(dfs)枚举子集会更快,虽然不知为何?

void dfs(int f,int sum,int k)
{
if (f>upb){
if (sum==-) return;
x=insHash(sum);
if (!gans) {
if (x<) x=-x;
if (k>cnt[x]) cnt[x]=k;
}
else if (x>&&cnt[x]+k>ans)
ans=cnt[x]+k;
else if (!sum&&k>ans) ans=k;
return;
}
dfs(f+,sum==-?num[f]:sum^num[f],k+);
dfs(f+,sum,k);
}

Meeting-in-the-Middle (LA 2965)的更多相关文章

  1. LA 2965 Jurassic Remains

    这是我做的第一道状态压缩的题目,而且我自己居然看懂了,理解得还算透彻. 题意:给出若干个大写字母组成的字符串,然后选取尽量多的字符串使得这些字母出现偶数次. 最朴素的想法,穷举法:每个字符串只有选和不 ...

  2. LA 2965 Jurassic Remains (中途相遇法)

    Jurassic Remains Paleontologists in Siberia have recently found a number of fragments of Jurassic pe ...

  3. UVa LA 2965 - Jurassic Remains 中间相遇,状态简化 难度: 2

    题目 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...

  4. LA 2965 中途相遇法

    题目链接:https://vjudge.net/problem/UVALive-2965 题意: 有很多字符串(24),选出一些字符串,要求这些字符串的字母都是偶数次: 分析: 暴力2^24也很大了, ...

  5. 【中途相遇+二进制】【NEERC 2003】Jurassic Remains

    例题25  侏罗纪(Jurassic Remains, NEERC 2003, LA 2965) 给定n个大写字母组成的字符串.选择尽量多的串,使得每个大写字母都能出现偶数次. [输入格式] 输入包含 ...

  6. 暑期培训7日游解题思路(day1~day3)

    暑期培训7日游解题思路(day1~day3) day1 第一天,王聿中老师出的题目比较简单,T1很水,T2是个简单的DP,T3还是有一点意思的.在网格图中删掉若干条边,使得所有格子都联通,求删掉的边的 ...

  7. SPOJ11469 SUBSET

    题面 Farmer John's owns N cows (2 <= N <= 20), where cow i produces M(i) units of milk each day ...

  8. UVALive - 2965 Jurassic Remains (LA)

    Jurassic Remains Time Limit: 18000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Sub ...

  9. Technical Committee Weekly Meeting 2016.06.21

    Meeting time: 2016.June.21 1:00~2:00 Chairperson:  Thierry Carrez Meeting summary: 1.Add current hou ...

随机推荐

  1. Python Requests post并将得到结果转换为json

    Python Requests post并将得到结果转换为json 学习了:https://blog.csdn.net/sinat_28680819/article/details/70940325  ...

  2. Node.js 替换文档内容

    server.js代码: var http=require('http'); var fs=require('fs'); var server=http.createServer(function(r ...

  3. Angular 学习笔记——sublime

    div.row>div.col-md-12*10 就等于 <div class="row">    <div class="col-md-12&q ...

  4. C连接MySql

    连接数据库connect.c #include <stdio.h> #include <mysql/mysql.h> int main() { //MYSQL句柄 MYSQL ...

  5. Unable to connect to a repository at URL 解决方法

    提示"Unable to connect to a repository at URL 'svn://localhost/project1/'" or “Can't connect ...

  6. 约瑟夫环用php实现

    百度百科的解释:约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数 ...

  7. appium----基本概念

    转:http://www.cnblogs.com/nbkhic/p/3803830.html Client/Server Architecture appium的核心其实是一个暴露了一系列REST A ...

  8. lvs+keepalived+bind实现负载均衡高可用智能dns

    整体架构: 1.IP地址规划: Dns1:172.28.0.54 Dns2:172.28.0.55 Dr服务器主:172.28.0.57 Dr服务器从:172.28.0.67 Vip:172.28.0 ...

  9. 第八章 委托,lamdbda 表达式和事件

    第八章 委托,lamdbda 表达式和事件 委托是寻址方式的.net版本. 委托是类型安全的类,它定义了返回类型和参数的类型.委托类不仅包含方法的应用,也可以包含对多个方法的引用. 在 C++中,函数 ...

  10. Android Studio 使用笔记:文件查询方法总结

    搜索单词 Windows: Ctrl + F Mac   : Cmd + F 会在当前激活的文件上查询输入的关键字,以高亮显示 跳转行 Windows: Ctrl + L Mac   : Cmd + ...