题目链接
题目描述:
定义两个位数相等的二进制串 A,B 的相似度 SIM(A,B)=二进制串A⊕B中0的个数。
如 A=00010,B=01000,A⊕B=01010,所以 SIM(A,B)=3。
给定 N 个长度为 M 的二进制串S1,S2…SN。
现在的问题是找出一个额外的长度为 M 的二进制字符串 T ,使得 max{SIM(S1,T),SIM(S2,T)…SIM(SN,T)}最小。
因为满足条件的 T 可能不止一个,不需要输出串 T ,只需要输出这个最小值即可。
输入描述:
第一行两个整数 N,M(1≤N≤3×105,1≤M≤20)。
然后 N 行,每行一个长度 M 为的字符串 Si 。
输出描述:
输出一行一个整数表示答案-- max{SIM(S1,T),SIM(S2,T)…SIM(SN,T)}的最小值。
题中有“最大个数最小”这么明显的字眼,我们首先想到的就是二分的思想,不错就是直接查找 T ,不过当然不能二分查找呀,我们需要查找长度为m的所有 01 字符串。但问题来了,我们怎么才能查找才符合“最大值”要求呢,我们可以把原有字符串通过特殊变换得到查找的 T ,那就把目标锁定在这个特殊变换上,0的最大个数,就是1的最小个数(因为总数是m),所以这个特殊变换就是对原字符串对某一位进行⊕1 ,就这样一代一代的推下去,知道把所有的长度为m的 01 字符串最大个数确定,最大个数最小值也就确定了,这就变成了一个 简单的bfs 问题,代码如下:
#include<cstdio>
#include<queue>
using namespace std;
const int N = 1 << 20;
inline int read(int xk = 10) { // quick read
int x = 0;
char ch = getchar();
while(ch <= '9' && ch >= '0') x=x*xk+ch-'0',ch=getchar();
return x;
}
struct node{
int s, v;// s代表字符串值,v代bfs深度
node(int s, int v):s(s), v(v){}
//v也代表T为时,1的最小个数,m-v也就是0的最大个数
};
bool visit[N];
queue<node>q;
int bfs(int m) {// bfs
int res = 0;
while(!q.empty()) {
node temp = q.front();
q.pop();
res = temp.v;
for(int i = 0; i < m; ++i) {
int k = temp.s ^ (1 << i);
if (!visit[k]) {
visit[k] = true;
q.push(node(k, temp.v + 1));
}
}
}
return m - res;
}
int main() {
int n, m;
n = read();
m = read();
for(int i = 1; i <= n; ++i) {
int k = read(2);
if(!visit[k]) {
visit[k] = true;
q.push(node(k, 0));
}
}
printf("%d\n", bfs(m));
return 0;
}