1. 程式人生 > >BZOJ2351 [BeiJing2011]Matrix 解題報告【資料結構】【Hash】

BZOJ2351 [BeiJing2011]Matrix 解題報告【資料結構】【Hash】

Description
給定一個M行N列的01矩陣,以及Q個A行B列的01矩陣,你需要求出這Q個矩陣哪些在原矩陣中出現過。
所謂01矩陣,就是矩陣中所有元素不是0就是1。
Input
輸入檔案的第一行為M、N、A、B,參見題目描述。
接下來M行,每行N個字元,非0即1,描述原矩陣。
接下來一行為你要處理的詢問數Q。
接下來Q個矩陣,一共Q*A行,每行B個字元,描述Q個01矩陣。
Output
你需要輸出Q行,每行為0或者1,表示這個矩陣是否出現過,0表示沒有出現過,1表示出現過。
Sample Input
3 3 2 2
111
000
111
3
11
00
11
11
00
11
Sample Output


1
0
1
HINT
對於100%的實際測試資料,M、N ≤ 1000,Q = 1000
對於40%的資料,A = 1。
對於80%的資料,A ≤ 10。
對於100%的資料,A ≤ 100。
題解
這道題是YYR上課的時候引用的。這道題無非就是考的一個行列hash的裸體。其中除了基礎的hash操作之外,如何加加減減使得我們的字首hash值變成部分hash值也是一個有趣的操作。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int N=1000
; const int BASE1=10016957; const int BASE2=10016959; const int Mod=10100; using namespace std; struct abcd{ unsigned num; int next; }table[N*N+5]; int m,n,a,b,q; unsigned int sum[N+5][N+5],power1[N+5],power2[N+5]; int hash_table[Mod],tot; void Hash(unsigned int x)//插入新的hash值 { int pos=x%Mod; table[++tot].num=x; table[tot].next=hash_table[pos]; hash_table[pos]=tot; } bool
Get_Hash(unsigned int x)//查詢其在hash表中的存在 { int pos=x%Mod; for(int i=hash_table[pos];i;i=table[i].next) if(table[i].num==x)return true; return false; } int main() { scanf("%d%d%d%d",&m,&n,&a,&b); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%1d",&sum[i][j]); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) sum[i][j]+=sum[i-1][j]*BASE1;//行hash for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) sum[i][j]+=sum[i][j-1]*BASE2;//列hash power1[0]=power2[0]=1; for(int i=1;i<=N;i++) power1[i]=power1[i-1]*BASE1,power2[i]=power2[i-1]*BASE2;//打表打出base的i次冪 for(int i=a;i<=m;i++) for(int j=b;j<=n;j++) { unsigned int temp=sum[i][j] -sum[i-a][j]*power1[a] -sum[i][j-b]*power2[b] +sum[i-a][j-b]*power1[a]*power2[b];//對字首hash值加加減減得到部分hash Hash(temp); } for(scanf("%d",&q);q;q--) { for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) scanf("%1d",&sum[i][j]); for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) sum[i][j]+=sum[i-1][j]*BASE1; for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) sum[i][j]+=sum[i][j-1]*BASE2; unsigned int temp=sum[a][b]; if(Get_Hash(temp))puts("1"); else puts("0"); } return 0; }

相關推薦

BZOJ2351 [BeiJing2011]Matrix 解題報告資料結構Hash

Description 給定一個M行N列的01矩陣,以及Q個A行B列的01矩陣,你需要求出這Q個矩陣哪些在原矩陣中出現過。 所謂01矩陣,就是矩陣中所有元素不是0就是1。 Input 輸入檔案

資料結構必備基礎知識之圖的基本概念詳解

一、前言 從今天開始就給大家分享有關於圖的概念和程式碼啦,不知道大家有沒有看夠樹的相關內容呢?以後還會慢慢給大家再分享的,程式碼要一遍一遍過,一輪一輪學習。第一輪樹就先到這裡,等第二輪還會給大家分享的。 圖應該是資料結構中處於霸王地位的一部分了,圖會涉及到圖論的相關知識,咱們現在還涉及不

資料結構週週練016 利用遞迴演算法及孩子兄弟表示法建立樹、遍歷樹並求樹的深度

一、前言 從今天起,就給大家分享一些樹的程式碼啦,不僅僅是二叉樹,我們要弄明白,普通的樹用資料結構怎麼儲存,它有哪些操作,它可以實現哪些功能? 可能大家要問了,二叉樹不是還沒有寫完嗎,線索二叉樹呢?二叉排序樹呢?平衡二叉樹呢?大家不要急,我們通過二叉樹來入門樹的演算法及程式碼實現,然後學

資料結構週週練015 利用遞迴演算法建立鏈式儲存的二叉樹並轉換左右孩子結點

一、前言 哈哈,今天就是程式設計師節啦,祝大家1024程式設計師節快樂。 今天要給大家分享的演算法是交換二叉樹是的左右孩子結點,比較簡單,需要建立一個結點用來暫存左孩子結點,下面給大家送上程式碼。 二、題目 將下圖用二叉樹存入,並交換二叉樹是的左右孩子結點。其中圓角矩形內為結點資

資料結構週週練014 利用棧和非遞迴演算法求鏈式儲存的二叉樹是否為完全二叉樹

一、前言 首先,明天是個很重要的節日,以後我也會過這個節日,在這裡,提前祝所有程式猿們,猿猴節快樂,哦不,是1024程式設計師節快樂。 今天要給大家分享的演算法是判斷二叉樹是否為完全二叉樹,相信大家對完全二叉樹的概念並不陌生,如果是順序儲存就會很方便,那鏈式儲存怎麼判斷呢,我的做法是:若

資料結構週週練013 利用棧和非遞迴演算法求二叉樹的高

一、前言 二叉樹的高是樹比較重要的一個概念,指的是樹中結點的最大層數本次演算法通過非遞迴演算法來求得樹的高度,借用棧來實現樹中結點的儲存。 學英語真的很重要,所以文中的註釋還有輸出以後會盡量用英語寫,文中出現的英語語法或者單詞使用錯誤,還希望各位英語大神能不吝賜教。 二、題目 將

資料結構週週練012 利用佇列和非遞迴演算法實現二叉樹的層次遍歷

一、前言 二叉樹的遍歷是比較多樣化的遍歷,有很多種遍歷方式,先序遍歷,中序遍歷,後序遍歷,層次遍歷等等。本次給大家講的是層次遍歷,為了方便,我將題目中的資料改為編號,從左往右,從上往下依次遍歷。方便大家看到結果。 二、題目 將下圖用二叉樹存入,並通過層次遍歷方式,自上而下,從左往右對

資料結構並查集POJ1988——線樹上的帶權並查集

問題描述: 給定30000個方塊,一開始每個方塊各自一摞,每次有兩種操作的方法,一種是將含有編號xx的一摞放在含有編號yy的一摞上,另一種是統計編號xx的方塊下有幾個方塊,每次將第二種操作的結果

資料結構與演算法01- 陣列、連結串列對比及應用

1. 陣列和連結串列的區別 1.1 底層儲存結構 陣列需要一塊連續的記憶體空間進行儲存 連結串列通過“指標”將一組零散的記憶體塊串聯起來使用 1.2 效能 連結串列和陣列的(增刪查)時間複雜度正好相反 陣列使用連續的記憶體空間,可以藉助快取機制提高效率

資料結構週週練001順序表與連結串列

目錄 前言 1、題目 2、程式碼 1、題目 2、程式碼 1、題目 2、程式碼 前言 從這周開始,我會不定期發一些資料結構練習題,一方面,提升自己的程式設計能力,給自己考研程式碼題打基礎,雖然邏輯都明白,但是一次性寫對程式碼還是有問題,

資料結構週週練005順序佇列與鏈隊 -撲克牌的篩選

沒有找到有關於佇列的經典題目,想到以前一個遊戲,覺得改編一下可以當作一道佇列的程式設計題來做。把這道題與自己的演算法分享給大家,如果大家有更好的演算法,歡迎大家一起交流討論。 由於普通佇列在實現時,採用順序儲存,會浪費掉大量的空間,所以一般在迴圈佇列採用順序儲存,普通佇列採

資料結構週週練010 遞迴演算法實現二叉樹的建立與遍歷

一、前言 上兩篇週週練部落格講了二叉樹的建立與遍歷,建立時,通過建立棧來存放結點,方便二叉樹的建立,這種建立二叉樹的方式採用了非遞迴演算法,本次內容採用遞迴的方式來建立二叉樹,大家可以通過對比程式碼量,感受一下遞迴的魅力。同時遍歷過程也是通過遞迴演算法。 如果大家第一次看

資料結構週週練017 利用遞迴演算法及孩子兄弟表示法建立森林、遍歷森林並求森林的葉子結點個數

 一、前言 從昨天起,就給大家分享一些樹和森林的程式碼啦,昨天分享的是求樹的深度,今天要給大家分享的是森林的遍歷以及求葉子的個數。 對於森林,大家可以做這樣的理解,一個深度大於1,根節點子樹個數大於1的樹去掉根節點,就是森林。森林中每棵樹的根節點再建立一個共同的雙親結點,

資料結構週週練020 利用遞迴判斷一棵二叉樹是否為二叉排序樹

一、二叉排序樹 二叉排序樹可以說是資料結構中相當重要的內容之一啦,前兩次給大家講了二叉排序樹的建立、遍歷與查詢。今天給大家分享的是二叉排序樹的應用,判斷一個二叉樹是否為一棵二叉排序樹。 二叉排序樹的特點大家都知道,左子樹根結點值<根結點<右子樹根結點值,並且中

資料結構週週練022 從大到小輸出二叉排序樹中小於某個值的所有結點編號及資料

一、二叉排序樹 今天給大家分享的是二叉排序樹的應用,從大到小輸出二叉排序樹中小於某個值的所有結點編號及資料。 我們知道,我們做中序遍歷時,先訪問左子樹,再訪問根節點,最後訪問右子樹;通過中序遍歷會得到一個遞增的序列。該應用要求得到從大到小,一個遞減的序列,我們可以通過先訪

資料結構和演算法062-3-4樹

    從第4節的分析中可以看出,二叉搜尋樹是個很好的資料結構,可以快速地找到一個給定關鍵字的資料項,並且可以快速地插入和刪除資料項。但是二叉搜尋樹有個很麻煩的問題,如果樹中插入的是隨機資料,則執行效果很好,但如果插入的是有序或者逆序的資料,那麼二叉搜尋樹的執行速度就變得很慢

資料結構和演算法14歸併排序

        歸併演算法的中心是歸併兩個已經有序的陣列。歸併兩個有序陣列A和B,就生成了第三個陣列C,陣列C包含陣列A和B的所有資料項,並且使它們有序的排列在陣列C中。首先我們來看看歸併的過程,然後看它是如何在排序中使用的。         假設有兩個有序陣列,不要求有相

資料結構和演算法17拓撲排序

        這一節我們學習一個新的排序演算法,準確的來說,應該叫“有向圖的拓撲排序”。所謂有向圖,就是A->B,但是B不能到A。與無向圖的區別是,它的邊在鄰接矩陣裡只有一項(友情提示:如果對圖這種資料結構部不太瞭解的話,可以先看一下這篇博文:資料結構和演算法之 無向

資料結構週週練034 奇偶排序演算法原理詳解及程式碼分享

一、氣泡排序 1、奇偶排序簡介 奇偶排序演算法不是嚴蔚敏老師書上的演算法,是今年某高校考研的一道考試題,聽朋友說了之後感覺很不錯,給大家分享一下。 題目大致含義如下: 已知奇偶交換排序如下所述: 1.第一趟對序列中所有奇數項i掃描,將a[i]和a[i+1]進行比較; 2.第二趟

資料結構與演算法分析1.2 編寫程式解決字謎問題

原博:http://blog.csdn.net/u013667086/article/details/49179741 問題描述:       從已知的字謎中找出在字典中的單詞 解決思路:        1、用指標陣列存放字謎和字典單詞        2、將字典單