洛谷 2258
Posted TSOI_Vergil
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 2258相关的知识,希望对你有一定的参考价值。
这道题我们一看数据范围第一感觉是状压DP,将每一列的选与不选看成是一个二进制数,但是这道题我们考虑如果知道了每一列选与不选,我们每一行的差值,现在问题就变成了在n列中选r行使其形成的矩阵值最小。我们可以考虑DP,F[i][j][k]表示在i这个状态,选了j行,最后一行选的是第k行,形成矩阵的最小值,转移模仿LIS的转移,我们可以预处理出合法的状态,然后再处理出在这个状态下任意两行相邻后的值,以及这个状态下每行的值,状态量最多是C(16,8),DP复杂度是O(n^3),勉强可以过掉。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int list[20000],tot;
int n,m,r,c,a[20][20],ans=1e9;
int g[20000][17][17],cha[20000][17],f[20000][17][17];
bool flag[17];
int main()
scanf("%d%d%d%d",&n,&m,&r,&c);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
int R=1<<m;
for (int i=1;i<R;i++)
int cnt=0;
for (int j=0;j<16;j++)
if (i&(1<<j))
cnt++;
flag[j+1]=1;
if (cnt==c)
list[++tot]=i;
for (int j=1;j<=n;j++)
for (int k=j+1;k<=n;k++)
for (int l=1;l<=m;l++)
if (flag[l])
g[tot][j][k]+=abs(a[j][l]-a[k][l]);
for (int j=1;j<=n;j++)
int temp=0;
for (int k=1;k<=m;k++)
if (flag[k])
if (temp!=0)
cha[tot][j]+=abs(a[j][k]-temp);
temp=a[j][k];
memset(flag,0,sizeof flag);
for (int i=1;i<=tot;i++)
for (int j=1;j<=r;j++)
for (int k=1;k<=n;k++)
f[i][j][k]=1e7;
for (int j=1;j<=r;j++)
for (int k=j;k<=n;k++)
for (int l=j-1;l<k;l++)
f[i][j][k]=min(f[i][j-1][l]+g[i][l][k]+cha[i][k],f[i][j][k]);
//printf("%d %d %d %d\\n",i,j,k,f[i][j][k]);
for (int j=1;j<=n;j++) ans=min(ans,f[i][r][j]);
printf("%d\\n",ans);
return 0;
以上是关于洛谷 2258的主要内容,如果未能解决你的问题,请参考以下文章