zoukankan      html  css  js  c++  java
  • P2258 子矩阵

    P2258 子矩阵

     题解

     这题的标签足以概括这道nice题目了

    就是考虑暴力枚举 ---> 先枚举行再枚举列

    ----->dp优化

    then  AC

    注释加在代码里了

    55'暴力代码

    //55'暴力
     
    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n,m,r,c;
    int a[20][20];
    int dph[20],dpl[20];
    //dph表示子矩阵的每一行的编号,dpl表示子矩阵的每一列的编号 
    int ans=0x7fffffff;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    void DP()
    {
        int now=0;  //当前得到一个完整的子矩阵,计算他的分数 
        for(int i=1;i<=r;i++)
          for(int j=2;j<=c;j++)
            now+=abs(a[dph[i]][dpl[j]]-a[dph[i]][dpl[j-1]]);
        for(int i=2;i<=r;i++)
          for(int j=1;j<=c;j++)
            now+=abs(a[dph[i]][dpl[j]]-a[dph[i-1]][dpl[j]]);
        ans=min(ans,now);
    } 
    
    void dfs(int x,int y,int rr,int cc)
    //当前走到了第x行,第y列,子矩阵已经枚举了rr行,cc列 
    {
        if(cc==c+1) return DP(); 
        //我们先枚举行,列枚举完了那么行一定也枚举完了,所以拿去跑一个ans 
        if((x>n&&rr!=r+1)||(y>m&&cc!=c+1)) return;
        //不合法情况直接退出 
        if(rr==r+1)  //行已经枚举够了 
        {
            for(int i=y;i<=m;i++)  //枚举列 
            {
                dpl[cc]=i;  //记录列 
                dfs(x,i+1,rr,cc+1);  //继续往下递归 
            }
    
        }
        else
        {
            for(int i=x;i<=n;i++)  //继续枚举行 
            {
                dph[rr]=i;  //记录行 
                dfs(i+1,y,rr+1,cc);  //继续往下递归 
            } 
    
        }
    }
    
    int main()
    {
        n=read();m=read();r=read();c=read();
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
             a[i][j]=read();
    
        dfs(1,1,1,1);
        
        printf("%d
    ",ans);
         
        return 0;
    }

    100‘ AC代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n,m,r,c;
    int a[20][20];
    int line[20],dp[20][20]; 
    //dp[i][j]表示前i列,已用j列得到的最小价值
    int updo[20],leri[20][20];
    //updo[i]表示对于i列的上下绝对值差的和,leri[i][j]表示i列和j列左右差的和 
    int ans=0x7fffffff;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    //转移方程 dp[i][j] = min(dp[i][j],dp[i-k][j-1]+ver[i]+del[i-k][i]}); 
    void DP()
    {
        memset(dp,63,sizeof(dp));
        memset(updo,0,sizeof(updo));
        memset(leri,0,sizeof(leri));
        
        for(int i=1;i<=m;i++) //枚举每一列i
          for(int j=2;j<=r;j++)
          updo[i]+=abs(a[line[j]][i]-a[line[j-1]][i]);//第i列的上下差值 
        
        for(int i=1;i<=m;i++)  //枚举每一列 
          for(int j=i+1;j<=m;j++)//枚举列,联系i,找差值 
             for(int k=1;k<=r;k++)//枚举子矩阵每一行 
             leri[i][j]+=abs(a[line[k]][j]-a[line[k]][i]);
        
        for(int i=1;i<=m;i++)
          dp[i][1]=updo[i];
        
        for(int i=1;i<=m;i++) //枚举每一列 
          for(int j=1;j<=c;j++) //子矩阵的每一列 
             for(int k=1;k<i&&i-k>=j-1;k++)
             //k一定要小于i(不然木得减了),i-k一定要大于等于j-1,因为j-1是从i-k行的当中挑出来的 
               dp[i][j]=min(dp[i][j],dp[i-k][j-1]+updo[i]+leri[i-k][i]);
                //dp取最小,比较(1),(2)
                //(1)dp[i][j]也就是上一轮循环到的自己
                //(2)从前i-k行中选j-1列,然后再选上当前这一列 
             
        for(int i=c;i<=m;i++)  //从c行后取最小值 
          ans=min(ans,dp[i][c]);
    }
    
    void dfs(int now ,int x)
    //子矩阵已经枚举了now行,当前走到了第x行 
    {
        if(now==r+1) return DP(); //已经枚举够行了 
        if(x>=n+1) return ;  //不合法直接退出 
        
        for(int i=x;i<=n;i++) //继续递归子矩阵的行 
        {
            line[now]=i;
            dfs(now+1,i+1);
        }
        
    }
    
    int main()
    {
        n=read();m=read();r=read();c=read();
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
             a[i][j]=read();
    
        dfs(1,1);
        
        printf("%d
    ",ans);
         
        return 0;
    }

    难得一见

    某谷又炸了

  • 相关阅读:
    linux并发控制之读写信号量
    linux并发控制之原子操作
    JAVA IntelliJ IDEA for mac/jdk的安装及环境配置、运行
    HDU2553 N皇后问题dfs
    LightOJ1282Leading and Trailing快速幂+数学
    HDU1226超级密码队列+广搜+大数取模
    Aizu ALDS1_13_A8 Queens Problem八皇后的路径输出
    HDU1548 A strange lift BFS
    POJ1182 食物链 并查集
    UVA10200Prime Time判断素数个数(打表预处理)+精度控制
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11126715.html
Copyright © 2011-2022 走看看