zoukankan      html  css  js  c++  java
  • TTTTTTTTTTTTTTTTTTTTT POJ 3690 0与* 二维哈希 模板 +multiset

    Constellations
    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
    ",++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
    ",++cas,t-st.size());
        }
        return 0;
    }
  • 相关阅读:
    C#实现-浏览器UA解析获得手机、系统、浏览器等信息
    C#代码实现-冒泡排序
    C# DateTime 工具类
    net core 3.1 跨域 Cors 找不到 “Access-Control-Allow-Origin”
    C#/.Net开发入门篇(3)——console类的输入输出
    C#/.Net开发入门篇(2)——第一个控制台应用程序
    C#/.Net开发入门篇(1)——开发工具安装
    docker 学习笔记(2)--docker file命令
    docker 学习笔记(1)--常用命令
    导出大数据方法。批量导BOM
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5545160.html
Copyright © 2011-2022 走看看