最小相似度 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;
}
发布了7 篇原创文章 · 获赞 5 · 访问量 514

猜你喜欢

转载自blog.csdn.net/Long_hen/article/details/105338009
o