zoukankan      html  css  js  c++  java
  • HDOJ1496 Equations【Hash】

    题目大意:

    有一个等式,

    a*x1^2+b*x2^2+c*x3^2+d*x4^2=0,

    a、b、c、d是[-50,50]之间的非零整数,

    有一组解析(x1,x2,x3,x4),其中xi是[-100,100]之间的非零整数,

    求有多少组解满足上式;

    输入:多组测试用例,每组测试用例包含4个数:a,b,c,d,他们之间用一个或多个空格隔开,EOF结尾;

    输出:每组测试用例解的个数;

    ==========基本思路=========

    4个循环嵌套,回溯;但是这样的复杂度是n^4,在本题中就是10000 0000数量级的~

    ==========改进思路=========

    把两项移到右边,就变成了左边两项与右边两项相等的式子;

    这样只要分别计算左右两边相等的可能性即可,这样的复杂度就是10000数量级了~

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

    a*x1^2 最大是50*10000 = 500000,其他三项也是,同理,最小是-500000;

    两项的最大就是1000000,最小就是-1000000,这样就需要一个2000000的hash表来存储了;

    但是要注意的是,最后hash表中存储的解得个数并不是最后结果,因为a、b、c、d四项可以互换位置,所以最后要乘以2^4 = 16才是解的个数;

    Problem : 1496 ( Equations )     Judge Status : Accepted
    RunId : 7413352    Language : C    Author : qq1203456195
    Code Render Status : Rendered By HDOJ C Code Render Version 0.01 Beta

    #include <stdio.h>
    #include <string.h>
    
    int arr[101];
    int hash[2000003];
    int main()
    {
        int a,b,c,d;
        int i,j,sum;
        for (i=1;i<101;i++)    arr[i] = i*i;
        while (scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF)
        {
            if ((a>0 && b>0 && c>0 && d>0) ||
                (a<0 && b<0 && c<0 && d<0))
            {
                printf("0\n");
                continue;
            }
            memset(hash,0,sizeof(hash));
            for (i=1;i<=100;i++)
            {
                for (j=1;j<=100;j++)
                {
                    hash[a*arr[i] + b*arr[j] + 1000000]++;
                }
            }
            sum = 0;
            for (i=1;i<=100;i++)
            {
                for (j=1;j<=100;j++)
                {
                    sum += hash[-(c*arr[i] + d*arr[j]) + 1000000];
                }
            }
            printf("%d\n",sum<<4);
        }
        return 0;
    }

     =======再次改进=======

    很明显,双重循环最多产生10000个数,所以开2000000个空间的数组明显是浪费了,怎样优化呢?1、数组,2、hash函数,3、冲突处理

    开小数组是必须的,但是并不是越小越好,因为还要考虑冲突的现象,但是具体取多少的?HDUACM的课件中开的是50021,这是一个较大的素数,这样key的位置就可以通过比较常用的除模取余方法来确定了。其实hash函数以及处理冲突的方法有很多,没有固定的方法。

    下边是HDUACM课件中使用的方法:

    int hash(int k)
    {
        int t=k%MAX;
        if(t<0)
            t+=MAX;
        while(f[t]!=0&&g[t]!=k)
            t=(t+1)%MAX;
        return t;
    }

    hash函数:t = k%MAX

    处理冲突的方法:t = (t+1)%MAX

    完整代码:f数组用来统计个数,g数组用来记录值;

    // by laili
    #include<stdio.h>
    #include<memory.h>
    
    #define MAX 50021
    
    int f[MAX],g[MAX];
    
    int hash(int k)
    {
        int t=k%MAX;
        if(t<0)
            t+=MAX;
        while(f[t]!=0&&g[t]!=k)
            t=(t+1)%MAX;
        return t;
    }
    
    int main()
    {
        int a,b,c,d,p,i,j,s,n,t[101];
        for(i=1;i<=100;i++)
            t[i]=i*i;
        while(scanf("%d%d%d%d",&a,&b,&c,&d)>0)
        {
                            ……
        }
    }

    while中代码:

    if(a>0&&b>0&&c>0&&d>0||a<0&&b<0&&c<0&&d<0)
            {
                printf("0\n");
                continue;
            }
            memset(f,0,sizeof(f));
            n=0;
            for(i=1;i<=100;i++)
                for(j=1;j<=100;j++)
                {
                    s=a*t[i]+b*t[j];
                    p=hash(s);
                    g[p]=s;
                    f[p]++;
                }
            for(i=1;i<=100;i++)
                for(j=1;j<=100;j++)
                {
                    s=-(c*t[i]+d*t[j]);
                    p=hash(s);
                    n+=f[p];
                }
            printf("%d\n",n*16);
    字节跳动内推

    找我内推: 字节跳动各种岗位
    作者: ZH奶酪(张贺)
    邮箱: cheesezh@qq.com
    出处: http://www.cnblogs.com/CheeseZH/
    * 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Mac 安装FFMpeg 与 FFmpeg 格式转换
    django channels
    python3 coroutine
    python中关于sql 添加参数
    python导包的问题
    python中的列表
    django中用model生成数据库表结构
    docker
    博客大神地址
    Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)
  • 原文地址:https://www.cnblogs.com/CheeseZH/p/2824091.html
Copyright © 2011-2022 走看看