題目鏈接
題目描述:
定義兩個位數相等的二進制串 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;
}