• Blue Mary的战役地图


    Blue Mary的战役地图( hash(starstar ))

    • 时限:(1s) 内存:(256M)

    Descrption

    • (Blue Mary) 最近迷上了玩 (Starcraft) (星际争霸) 的 (RPG) 游戏。她正在设法寻找更多的战役地图以进一步提高自己的水平。
    • 由于 (Blue Mary) 的技术已经达到了一定的高度,因此,对于用同一种打法能够通过的战役地图,她只需要玩一张,她就能了解这一类战役的打法,然后她就没有兴趣再玩儿这一类地图了。而网上流传的地图有很多都是属于同一种打法,因此 (Blue Mary) 需要你写一个程序,来帮助她判断哪些地图是属于同一类的。
    • 具体来说,(Blue Mary) 已经将战役地图编码为 (n imes n) 的矩阵,矩阵的每个格子里面是一个 (32) 位(有符号)正整数。对于两个矩阵,他们的相似程度定义为他们的最大公共正方形矩阵的边长。两个矩阵的相似程度越大,这两张战役地图就越有可能是属于同一类的。

    Input

    • 输入文件的第一行包含一个正整数 (n)
    • 以下 (n) 行,每行包含 (n) 个正整数,表示第一张战役地图的代表矩阵。
    • 再以下 (n) 行,每行包含 (n) 个正整数,表示第二张战役地图的代表矩阵。

    Output

    • 输出文件仅包含一行。这一行仅有一个正整数,表示这两个矩阵的相似程度。

    Sample Input

    3
    1 2 3
    4 5 6
    7 8 9
    5 6 7
    8 9 1
    2 3 4
    

    Sample Output

    2
    

    Hint

    • 子矩阵:

      5 6

      8 9

      为两个地图的最大公共矩阵

    • 对于(30\%) 的数据 (1<=n<=50)

    • 对于 (60\%) 的数据 (1<=n<=200)

    • 对于 (100\%) 的数据 (1<=n<=500)

    • 来源:(luogup4398)

    分析

    • 方法一:(dp)
      • 此题很像线性 (dp) 的求最长公共子串。但不同的是此题是二维矩阵,我们可以参照最长公共子串的模型定义出状态:(dp[x1][y1][x2][y2]) 表示第一个矩阵的右下角坐标为 ((x1,y1)) ,第二个矩阵的右下角坐标为 ((x2,y2)) 公共正方形最大的边长。则有状态转移方程:
      • (dp[x1][y1][x2][y2]=min(dp[x1-1][y1-1][x2-1][y2-1],min(dp[x1][y-1][x2][y2-1],dp[x1-1][y1][x2-1][y2])))
      • ((x1,y1),(x2,y2)) 为右下角的最大公共子矩阵要看以当前点的左边,正上,左上为右下角的三个公共矩阵中最小的再加上 (1),这个 (1) 就是当前点坐在的行和列。
      • 这是这类题的典型做法,但实在对不起,(nle 100) ,(n^4) 有点悬,不过本服务器还是能压过。

    Code

    #include<bits/stdc++.h>
    const int maxn=101,Inf=0x3f3f3f3f;
    int dp[maxn][maxn][maxn][maxn];
    int n,a[maxn][maxn],b[maxn][maxn];
    void Init(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&a[i][j]);
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&b[i][j]);
    }
    void Solve(){
        int ans=0;
        for(int x1=1;x1<=n;++x1)
            for(int y1=1;y1<=n;++y1)
                for(int x2=1;x2<=n;++x2)
                    for(int y2=1;y2<=n;++y2)
                        if(a[x1][y1]==b[x2][y2]){
                            dp[x1][y1][x2][y2]=std::min(dp[x1-1][y1-1][x2-1][y2-1],std::min(dp[x1][y1-1][x2][y2-1],dp[x1-1][y1][x2-1][y2]))+1;
                            ans=std::max(ans,dp[x1][y1][x2][y2]);
                        }
        printf("%d
    ",ans);
    }
    int main() {
        Init();
        Solve();
        return 0;
    }
    

    方法二: (hash)

    • 二维 (hash)

    • (Code)

      #include<bits/stdc++.h>
      typedef unsigned long long uLL;
      const int maxn=101,Inf=0x3f3f3f3f;
      const uLL RowBase=11,ColBase=13;
      int n;
      uLL Row[maxn],Col[maxn];
      uLL a[maxn][maxn],b[maxn][maxn];
      void Init(){
          scanf("%d",&n);
          for(int i=1;i<=n;++i)
              for(int j=1;j<=n;++j)
                  scanf("%lld",&a[i][j]);
          for(int i=1;i<=n;++i)
              for(int j=1;j<=n;++j)
                  scanf("%lld",&b[i][j]);
          Row[0]=Col[0]=1;//Row:行基数,Col:列基数
          for(int i=1;i<=n;++i)//Row[i]表示第i位的以RowBase为进制的基数
              Row[i]=Row[i-1]*RowBase;
          for(int i=1;i<=n;++i)
              Col[i]=Col[i-1]*ColBase;
      }
      uLL Calc(uLL a[][maxn],int x,int y,int h){//二维哈希的标准姿势
          return a[x][y]-a[x-h][y]*Col[h]-a[x][y-h]*Row[h]+a[x-h][y-h]*Row[h]*Col[h];
      }
      void Solve(){
          for(int i=1;i<=n;++i)//把每一行压缩成一个RowBase进制数
              for(int j=1;j<=n;++j)
                  a[i][j]=a[i][j-1]*RowBase+a[i][j];
          for(int i=1;i<=n;++i)//压缩列
              for(int j=1;j<=n;++j)
                  a[i][j]=a[i-1][j]*ColBase+a[i][j];
          std::map<uLL,bool> mp;
          for(int h=0;h<=n;++h)//正方形边长
              for(int i=h;i<=n;++i)//i,j为正方形的右下角
                  for(int j=h;j<=n;++j)
                      mp[Calc(a,i,j,h)]=1;//赋值为什么都可以,只要有就行
          for(int i=1;i<=n;++i)
              for(int j=1;j<=n;++j)
                  b[i][j]=b[i][j-1]*RowBase+b[i][j];
          for(int i=1;i<=n;++i)
              for(int j=1;j<=n;++j)
                  b[i][j]=b[i-1][j]*ColBase+b[i][j];
          for(int h=n;h>=0;--h)//注意h可以为0,因为可能没有相同的元素
              for(int i=h;i<=n;++i)
                  for(int j=h;j<=n;++j)
                      if(mp.find(Calc(b,i,j,h))!=mp.end()){
                          printf("%d
      ",h);return;
                      }
      }
      int main() {
          Init();
          Solve();
          return 0;
      }
      
  • 相关阅读:
    PS转换图片——我教你
    通过Ajax——异步获取相关问题解答
    Spring的线程安全
    Spring MVC的工作机制
    Annotation的语法和使用
    Spring Bean的生命周期
    浅谈Spring
    Spring的事务管理
    行为型模式
    结构型模式
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13402986.html
Copyright © 2020-2023  润新知