[NOIP2014]子矩阵
1812. [NOIP2014]子矩阵
http://www.cogs.pro/cogs/problem/problem.php?pid=1812
★★★ 输入文件:submatrix.in
输出文件:submatrix.out
简单对比
时间限制:1 s 内存限制:256 MB
【题目描述】
最暴力的算法是枚举选择哪些行、列。复杂度为O(C(n,r)*C(m,c))。不过显然不能承受。(C为组合数)
注意到虽然O(C(n,r)*C(m,c))不能承受,但O(C(n,r))或O(C(m,c))是可以接受的。
不妨考虑枚举其中一个(假设枚举行)。
枚举完行后,由于行已确定,因此可以把所有行捆绑,视为一个整体。
处理处列与列之间的价值,然后可以用动态规划解决这个问题。
设dp[i][k]表示前i列选了k列,并且第i列强制被选。那么转移方程为:dp[i][k]=dp[j][k-1]+cost[j][i]+val[i],其中j<i,cost[j][i]表示第i列与第j列相邻的花费,val[i]表示第i列内的花费。
答案即为min{dp[i][c]}。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> using namespace std; int a[20][20],m,n,r,c,lr[20],ud[20],dp[20][20]; int rlc[20],udc[20][20],ans=0x7fffffff; void Dp(){ memset(rlc,0,sizeof(rlc)); memset(udc,0,sizeof(udc)); memset(dp,127/3,sizeof(dp)); //不同列之间的差 for(int i=1;i<=m;i++) for(int j=1;j<i;j++) for(int k=1;k<=r;k++) udc[j][i]+=abs(a[lr[k]][i]-a[lr[k]][j]); //不同行之间的差 for(int i=1;i<=m;i++) for(int j=1;j<r;j++) rlc[i]+=abs(a[lr[j]][i]-a[lr[j+1]][i]); for(int i=1;i<=n;i++)dp[i][0]=0,dp[i][1]=rlc[i]; for(int i=1;i<=c;i++){ for(int j=i;j<=m;j++){ for(int k=i-1;k<j;k++){ dp[j][i]=min(dp[k][i-1]+udc[k][j]+rlc[j],dp[j][i]); } } } for(int i=c;i<=m;i++)ans=min(ans,dp[i][c]); } void dfs(int Step,int rest){ if(Step==r){Dp();return;} if(r-Step>rest)return; for(int i=rest;i>=1;i--){lr[Step+1]=i;dfs(Step+1,i-1);} } int main(){ freopen("submatrix.in","r",stdin); freopen("submatrix.out","w",stdout); 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]); dfs(0,n); printf("%d",ans); }