POJ 3690 0与* 二维哈希 模板 +multiset
Posted smilesundream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3690 0与* 二维哈希 模板 +multiset相关的知识,希望对你有一定的参考价值。
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 5923 | Accepted: 1164 |
Description
The starry sky in the summer night is one of the most beautiful things on this planet. People imagine that some groups of stars in the sky form so-called constellations. Formally a constellation is a group of stars that are connected together to form a figure or picture. Some well-known constellations contain striking and familiar patterns of bright stars. Examples are Orion (containing a figure of a hunter), Leo (containing bright stars outlining the form of a lion), Scorpius (a scorpion), and Crux (a cross).
In this problem, you are to find occurrences of given constellations in a starry sky. For the sake of simplicity, the starry sky is given as a N× M matrix, each cell of which is a ‘*‘ or ‘0‘ indicating a star in the corresponding position or no star, respectively. Several constellations are given as a group of T P × Q matrices. You are to report how many constellations appear in the starry sky.
Note that a constellation appears in the sky if and only the corresponding P × Q matrix exactly matches some P × Q sub-matrix in the N ×M matrix.
Input
The input consists of multiple test cases. Each test case starts with a line containing five integers N, M, T, P and Q(1 ≤ N, M ≤ 1000, 1 ≤ T≤ 100, 1 ≤ P, Q ≤ 50).
The following N lines describe the N × M matrix, each of which contains M characters ‘*‘ or ‘0‘.
The last part of the test case describe T constellations, each of which takes P lines in the same format as the matrix describing the sky. There is a blank line preceding each constellation.
The last test case is followed by a line containing five zeros.
Output
For each test case, print a line containing the test case number( beginning with 1) followed by the number of constellations appearing in the sky.
Sample Input
3 3 2 2 2 *00 0** *00 ** 00 *0 ** 3 3 2 2 2 *00 0** *00 ** 00 *0 0* 0 0 0 0 0
Sample Output
Case 1: 1 Case 2: 2
Source
题意:给定一个n*m矩阵和t个p*q的矩阵,求这t个矩阵有多少个是n*m的子矩阵。
矩阵都是01矩阵,只有‘0‘ ‘*‘
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int inf =0x7f7f7f7f;
const double pi=acos(-1);
const int maxn=5+1000;
int ans=inf;
int n,m,t,p,q,cas=0;
char text[maxn][maxn];
ull b1[1004],b2[1004];
char pat[55][55];
ull htmp[1005][1005],h[1005][1005];
ull base1=1e7+7;
ull base2=1e8+7;
void init()
{
b1[0]=1;b2[0]=1;
for(int i=1;i<1003;i++) b1[i]=b1[i-1]*base1;
for(int i=1;i<1003;i++) b2[i]=b2[i-1]*base2;
}
ull calhash1()
{
ull res=0;
for(int i=0;i<p;i++)
{
ull k=0;
for(int j=0;j<q;j++)
k=k*base1+pat[i][j];
res=res*base2+k;
}
return res;
}
void calhash2()
{
for(int i=0;i<n;i++)
{
for(int j=0;j<q;j++) htmp[i][j]=j==0?text[i][j]:htmp[i][j-1]*base1+text[i][j];
for(int j=q;j<m;j++) htmp[i][j]=htmp[i][j-1]*base1+text[i][j]-text[i][j-q]*b1[q];
}
for(int j=0;j<m;j++)
{
for(int i=0;i<p;i++) h[i][j]=i==0?htmp[i][j]:h[i-1][j]*base2+htmp[i][j];
for(int i=p;i<n;i++) h[i][j]=h[i-1][j]*base2+htmp[i][j]-htmp[i-p][j]*b2[p];//求前缀
}
}
multiset<ull> st;
int main()
{
init();
int cas=0;
while(~scanf("%d%d%d%d%d",&n,&m,&t,&p,&q)&&(n+m+t+p+q))
{
st.clear();
for(int i=0;i<n;i++)
scanf("%s",text[i]);
for(int k=0;k<t;k++)
{
for(int i=0;i<p;i++)
scanf("%s",pat[i]);
st.insert(calhash1());
}
calhash2();
int ans=0;
for(int i=p-1;i<n;i++)
for(int j=q-1;j<m;j++)
st.erase(h[i][j]);
printf("Case %d: %d\n",++cas,t-st.size());
}
return 0;
}
错误点:
for(int i=p;i<n;i++) h[i][j]=h[i-1][j]*base2+htmp[i][j]-htmp[i-p][j]*b2[p]
刚开始写成了htmp[i][j]=htmp[i-1][j]*base2+htmp[i][j]-htmp[i-p][j]*b2[p]
其实这样是不对的,因为这样的话htmp是代表的前缀,所以一个数会减去多次,,所以需要建立一个新的h数组
wa代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <queue> #include <stack> #include <map> #include <algorithm> #include <set> using namespace std; typedef long long ll; typedef unsigned long long ull; #define MM(a,b) memset(a,b,sizeof(a)); const double eps = 1e-10; const int inf =0x7f7f7f7f; const double pi=acos(-1); const int maxn=5+1000; int ans=inf; int dx[6]={-1,0,1,0}; int dy[6]={0,1,0,-1}; int n,m,t,p,q,cas=0; char text[maxn][maxn]; ull b1[1004],b2[1004]; char pat[1005][1005]; ull has[1005][1005]; ull base1=131; ull base2=499; void init() { b1[0]=1;b2[0]=1; for(int i=1;i<1003;i++) b1[i]=b1[i-1]*base1; for(int i=1;i<1003;i++) b2[i]=b2[i-1]*base2; } ull H[1005][1005]; ull calhash1() { ull res=0; for(int i=0;i<p;i++) { ull k=0; for(int j=0;j<q;j++) k=k*base1+pat[i][j]; res=res*base2+k; } return res; } void calhash2() { for(int i=0;i<n;i++) { for(int j=0;j<q;j++) has[i][j]=j==0?text[i][j]:has[i][j-1]*base1+text[i][j]; for(int j=q;j<m;j++) has[i][j]=has[i][j-1]*base1+text[i][j]-text[i][j-q]*b1[q]; } for(int j=0;j<m;j++) { for(int i=0;i<p;i++) has[i][j]=i==0?has[i][j]:has[i-1][j]*base2+has[i][j]; for(int i=p;i<n;i++) has[i][j]=has[i-1][j]*base2+has[i][j]-has[i-p][j]*b2[p]; } } set<ull> st; int main() { init(); int cas=0; while(~scanf("%d%d%d%d%d",&n,&m,&t,&p,&q)&&(n+m+t+p+q)) { st.clear(); for(int i=0;i<n;i++) scanf("%s",text[i]); for(int k=0;k<t;k++) { for(int i=0;i<p;i++) scanf("%s",pat[i]); st.insert(calhash1()); } calhash2(); int ans=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(st.count(has[i][j])) st.erase(has[i][j]); printf("Case %d: %d\n",++cas,t-st.size()); } return 0; }
以上是关于POJ 3690 0与* 二维哈希 模板 +multiset的主要内容,如果未能解决你的问题,请参考以下文章