贪心+枚举/哈希表 HDOJ Trouble

题目传送门

题意:5个集合,每个集合最多200个数字,问是否每个集合挑一个数加起来和为0。

分析:显然n^5的程序果断超时,甚至n^3logn的二分也过不了。想n^3的方法,既然判断有没有,那么可以将两个两个的集合合并成两个大集合,再枚举最后一个集合,两个大集合排完序之后一个指针从开头最小开始,另一个从最大的开始,>0,大指针往左移,<0,小指针往右移,那么可以在线性时间求解,这贪心方法很巧妙!

另一种做法算是暴力+优化了,哈希表储存一个两个集合合并后大集合的数字,n^3暴力询问是否哈希表内存在它的相反数,哈希表用到链式前向星,总算有点理解了,贴张图:

收获:1. ”微调“贪心方法 2. 哈希表 + 链式前向星

代码1(贪心):

/************************************************
 * Author        :Running_Time
 * Created Time  :2015-8-26 9:07:01
 * File Name     :HDOJ_4334.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 2e2 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
ll a[5][N];
ll sum[2][N*N];

int main(void)    {
    int T; scanf ("%d", &T);
    while (T--) {
        int n;  scanf ("%d", &n);
        for (int i=0; i<5; ++i) {
            for (int j=0; j<n; ++j) {
                scanf ("%I64d", &a[i][j]);
            }
        }
        int tot = 0;
        for (int i=0; i<n; ++i) {
            for (int j=0; j<n; ++j) {
                sum[0][tot] = a[0][i] + a[1][j];
                sum[1][tot++] = a[2][i] + a[3][j];
            }
        }
        sort (sum[0], sum[0]+tot);
        sort (sum[1], sum[1]+tot);
        int cnt1 = 1, cnt2 = 1;
        for (int i=1; i<tot; ++i) {                                     //其实离散化没什么优化
            if (sum[0][i] != sum[0][i-1])   sum[0][cnt1++] = sum[0][i];
            if (sum[1][i] != sum[1][i-1])   sum[1][cnt2++] = sum[1][i];
        }

        bool flag = false;
        for (int i=0; i<n && !flag; ++i) {
            for (int j=0,k=cnt2-1; j<cnt1 && k>=0; )  {
                ll tmp = a[4][i] + sum[0][j] + sum[1][k];
                if (tmp == 0)   {
                    flag = true;    break;
                }
                else if (tmp < 0)   j++;
                else    k--;
            }
        }

        printf ("%s\n", flag ? "Yes" : "No");
    }

    return 0;
}

代码2(哈希表):

/************************************************
* Author        :Running_Time
* Created Time  :2015-8-26 18:21:55
* File Name     :D_2.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 2e2 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e6 + 7;
struct Hash_Table   {
    struct Edge {
        ll x;
        int nex;
    }edge[MOD];
    int head[MOD], E;
    void init(void) {
        memset (head, -1, sizeof (head));
        E = 0;
    }
    void insert(ll x)   {
        int u = (x % MOD + MOD) % MOD;
        for (int i=head[u]; ~i; i=edge[i].nex)  {
            if (edge[i].x == x) return ;
        }
        edge[E].x = x;  edge[E].nex = head[u];
        head[u] = E++;
    }
    bool find(ll x) {
        int u = (x % MOD + MOD) % MOD;
        for (int i=head[u]; ~i; i=edge[i].nex)  {
            if (edge[i].x == x) return true;
        }
        return false;
    }
}ha;
ll a[5][N];

int main(void)    {
    int T;  scanf ("%d", &T);
    while (T--) {
        int n;  scanf ("%d", &n);
        for (int i=0; i<5; ++i) {
            for (int j=0; j<n; ++j) scanf ("%I64d", &a[i][j]);
        }
        ha.init ();
        for (int i=0; i<n; ++i) {
            for (int j=0; j<n; ++j) {
                ha.insert (a[0][i] + a[1][j]);
            }
        }
        bool flag = false;
        for (int i=0; i<n && !flag; ++i) {
            for (int j=0; j<n && !flag; ++j) {
                for (int k=0; k<n; ++k) {
                    if (ha.find (-(a[2][i] + a[3][j] + a[4][k])))   {
                        flag = true;    break;
                    }
                }
            }
        }
        puts (flag ? "Yes" : "No");
    }

    return 0;
}

  

时间: 2024-11-07 05:53:35

贪心+枚举/哈希表 HDOJ Trouble的相关文章

Stack集合 Queue队列集合 Hashtable哈希表

Stack集合 干草堆集合 栈集合 栈;stack,先进后出,一个一个赋值,一个一个取值,安装顺序来. 属性和方法 实例化 初始化 Stack st = new Stack(); 添加元素 1 个数 2 Console.WriteLine(st.Count); 3 只要使用一次pop方法,就会从最后一个元素开始排除 弹出 4 Console.WriteLine(st.Pop()); 5 Console.WriteLine(st.Count); 6 只想查看不弹出 7 Console.WriteL

哈希表(转)

JAVA哈希表 哈希表是一种重要的存储方式,也是一种常见的检索方法.其基本思想是将关系码的值作为自变量,通过一定的函数关系计算出对应的函数值,把这个数值解释为结点的存储地址,将结点存入计算得到存储地址所对应的存储单元.检索时采用检索关键码的方法.现在哈希表有一套完整的算法来进行插入.删除和解决冲突.在Java中哈希表用于存储对象,实现快速检索. Java.util.Hashtable提供了种方法让用户使用哈希表,而不需要考虑其哈希表真正如何工作. 哈希表类中提供了三种构造方法,分别是: publ

哈希表入门讲解

散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构.也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度.这个映射函数称做散列函数,存放记录的数组称做散列表. 一个通俗的例子是,为了查找电话簿中某人的号码,可以创建一个按照人名首字母顺序排列的表(即建立人名{\displaystyle x}到首字母{\displaystyle F(x)}的一个函数关系),在首字母为W的表中查找"王"姓的电话号

noip模拟赛 好元素 哈希表的第一题

这是一道关于 题2好元素 2s [问题描述] 小A一直认为,如果在一个由N个整数组成的数列{An}中,存在以下情况: Am+An+Ap = Ai (1 <= m, n, p < i <= N , m,n,p可以相同),那么Ai就是一个好元素. 现在小A有一个数列,请你计算数列中好元素的数目 [输入格式] 第一行只有一个正整数N,意义如上. 第二行包含N个整数,表示数列{An}. [输出格式] 输出一个整数,表示这个数列中好元素的个数. [输入样例] Sample1 2 1 3 Sampl

【BZOJ2081】Beads(哈希表)

题意: 翻转是指其中一段长度为k的子串全部翻转 n<=200000 a[i]<=n 思路:枚举k,直接哈希判充即可 时间复杂度是n/i求和,根据定理可得是O(n log n)级别的 单哈双哈都可能被卡,我用的是单哈+哈希表判重 1 const mo=250109; 2 var h1,h2,mi,c,a,head,vet,next:array[0..1000000]of longint; 3 n,i,p,j,st,ed,t1,t2,t3,l,ans,tot:longint; 4 5 functi

哈希表和字典的应用

Egg: string x = string.Empty;                string y = string.Empty;                Hashtable ht = new Hashtable();                ht.Add("12", "ab");                ht.Add("34", "cd");                foreach (Dict

哈希表——swift字典的实现原理

我们先看看维基百科的介绍 散列表(Hash table,也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构.也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度.这个映射函数称做散列函数,存放记录的数组称做散列表. 一个通俗的例子是,为了查找电话簿中某人的号码,可以创建一个按照人名首字母顺序排列的表(即建立人名到首字母的一个函数关系),在首字母为W的表中查找"王"姓的电话号码,显然比直接查找就要快得多.这

POJ2002_Squares (哈希表)

本文出自:blog.csdn.net/svitter 题意 A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degree angles. It is also a polygon such that rotating about its centre by 90 degrees gives the same polygon. It is not the only poly

POJ 3349 Snowflake Snow Snowflakes(哈希表)(转)

题意:判断有没有两朵相同的雪花.每朵雪花有六瓣,比较花瓣长度的方法看是否是一样的,如果对应的arms有相同的长度说明是一样的.给出n朵,只要有两朵是一样的就输出有Twin snowflakes found.,如果任何两个都是不一样的输出No two snowflakes are alike.n=100,000. 思路:最 简单的就是枚举每两片雪花,判断他们是否相同.时间复杂度为O(n*n),显然效果不理想.有没有更好的算法呢?hash:每读进一片雪花,将雪花 hash,判断hash表里是否有相同