Hdu4712 Hamming Distance ---- 多向BFS

题目链接:HDU 4712

看评论里面很多人都是用随即算法过的     在这里贴一个非随即算法的解法


题意:给你n个(n<=1e5)数a0~a(n-1)(ai<(1<<20))   要你求这n个数中转化为二进制后任意两个数中最小的汉明距离    \\  wiki百科:汉明距离

例如:a0 = 00000000010000000000   a1 = 00000000000000000001   a2 = 00000000000000000011

则答案为1 , 因为 a1^a2 = 00000000000000000010 其中1的个数为1,则答案为1


思路:

先说下随即算法的思路:首先当n比较小的时候,直接暴力枚举每两个数,求最小的汉明距离即可;当n比较大时,每次直接随即选出两个数a,b,求出汉明距离选取最小的即可。

因为ai<(1<<20),说明最终解一定<=20,解的范围很小,所以随即算法成功的几率还是很高的。

======================================================================================


接下来说说非随即算法(全是个人独立想出的哦)

首先要利用汉明距离的一个性质,二进制字符串的汉明距离也等于 n 维超正方体两个顶点之间的曼哈顿距离,其中n 是两个字串的长度。

我们先令(a,b)表示二进制字符a,b的汉明距离!!

怎么解释那个性质呢,就是比如有a,b,c三个二进制字符,其中(a,b)==(b,c)==1,那么(a,c) = (a,b)+(b,c) = 2

再加入一个d,假设(c,d)==1,且(d,a)!=1且(d,b)!=1,那么(d,a) = (a,b)+(b,c)+(c,d) = 3; (d,b) = (b,c)+(c,d) = 2;

(对于这个性质我一开始也是猜测,然后写了个小程序简单验证了一下,再后来仔细看汉明距离的wiki百科的时候才发现上面写着有。。。

怪不得题目上面一开始就表明了(From WIKI)。。。  )


有了这个性质接下来的事情就比较简单了

因为a<(1<<20),所以先把这(1<<20)个数当成(1<<20)个结点,然后把其汉明距离为1的结点连接起来,把边的长度设为1,

这样两个数的汉明距离即为这个图上两点间的最短路长度

如此一来,我们就可以把给出的n个数当成n个起点,然后在图上进行搜索,搜出任意两起点间最短的距离

搜索的方法就类似于多向BFS,具体的实现见代码

PS:多向BFS在搜索时,搜索到一个解并不能马上返回,需要把当前这一层的结点搜索完毕,然后返回一个最优值

比如下面这个图

可以尝试模拟一下,其中1,2,3表示搜索起点,当搜索到4号结点的时候,如果先行搜索红色边的话,则返回值是4,而正确解应该是3

Hdu4712 Hamming Distance ---- 多向BFS_第1张图片



下面贴代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define FOR(i,j,k) for(int i=j;i<=(k);i++)
#define ll long long
#define base 20
#define maxn (1<='0'&&c<='9')  return c-'0';
    return 10+c-'A';
}
void Input(int k){
    char s[7];
    cin >> s;
    int st = 0;
    REP(i,5) {
        st *= 16;
        st += Hash(s[i]);
    }
    a[k] = st;
}

int dis[maxn],color[maxn];//dis表示距离,color相当于把从每个起点开始的搜索路径染色
queue  q;
int Solve(){
    while(!q.empty())   q.pop();
    memset(color,-1,sizeof(color));
    memset(dis,-1,sizeof(dis));
    REP(i,n){
        if(dis[a[i]] != -1) return 0;
        dis[a[i]] = 0;
        color[a[i]] = i;
        q.push(a[i]);
    }
    int ans = 2e9,floor = 2e9;  // ans 是答案 floor表示的是限定得到解的层数
    while(!q.empty()){
        int u = q.front(); q.pop();
        REP(i,base){
            int v = (u^(1<> test;
    while(test --){
        cin >> n;
        memset(a,-1,sizeof(a));
        REP(i,n)    Input(i);
        cout << Solve() << endl;
    }
}


你可能感兴趣的:(ACM)