最小相似度 bfs O(∩_∩)O哈哈~

題目鏈接

題目描述:

定義兩個位數相等的二進制串 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章