洛谷 P2258 子矩阵

传送门:洛谷 P2258 子矩阵
算法分析:
本题要求某个子矩阵,则有两个变量:所选的 \(l\)\(r\)
考虑用 \(DFS\) (全排列)和 \(DP\) 来解决本题
先生成行的全排列,接着就可以得到 \(r\times m\) 的矩阵,用区间\(DP\)处理一遍即可


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxN=16,maxNUM=12870;
int n,m,r,c,map[maxN+1][maxN+1];
int a[maxNUM+1][maxN+1],heng[maxN+1];
int zong[maxN+1][maxN+1];
int maze[maxN+1][maxN+1],dp[maxN+1][maxN+1];
int way=0,ways[maxNUM+1],total,len=1,ans=2147483647;
inline int read();
void dfs(int,int);
long long frac(long long);
void work();
int main()
{
    n=read(); m=read();
    r=read(); c=read();
    total=frac(n)/(frac(r)*frac(n-r));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            map[i][j]=read();
    dfs(1,0);
    for(int i=1;i<=total;i++)
    {
        memset(dp,127,sizeof(dp));
        len=0;
        for(int j=1;j<=r;j++)
        {
            len++;
            for(int k=1;k<=m;k++)
                maze[len][k]=map[a[i][j]][k];
        }
        work();
        for(int i=c;i<=m;i++)
            ans=min(ans,dp[c][i]);
    }
    printf("%d",ans);
    return 0;
}
void work()
{
    memset(heng,0,sizeof(heng));
    memset(zong,0,sizeof(zong));
    memset(dp,127,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=m;i++)
        for(int j=1;j<r;j++)
            heng[i]+=abs(maze[j][i]-maze[j+1][i]);
    for(int i=1;i<=m;i++)
        for(int j=i+1;j<=m;j++)
            for(int k=1;k<=r;k++)
                zong[i][j]+=abs(maze[k][i]-maze[k][j]);
    for(int i=1;i<=c;i++)
        for(int j=i;j<=m;j++)
            for(int k=0;k<j;k++)
                dp[i][j]=min(dp[i][j],dp[i-1][k]+heng[j]+zong[k][j]);
}
long long frac(long long x)
{
    long long ans=1;
    for(long long i=2;i<=x;i++) ans*=i;
    return ans;
}
void dfs(int start,int step)
{
    if(step==r)
    {
        way++;
        for(int i=0;i<r;i++)
            a[way][i+1]=ways[i];
        return;
    }
    for(int i=start;i<=n;i++)
    {
        ways[step]=i;
        dfs(i+1,step+1);
    }
}
inline int read()
{
    int num=0,f=1;
    char ch=getchar();
    while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    if(ch=='-') {f=-1; ch=getchar();}
    while(ch>='0' && ch<='9')
    {
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

猜你喜欢

转载自www.cnblogs.com/ezsyshx/p/10359343.html