P2258 子矩阵

子矩阵

思路

很容易想到这是一个动态规划,但是从题目来分析,不能很容易的设计出状态转移方程。

原题为从矩阵中选出r行c列

我们可以将问题进行化简,先对于原题进行dfs枚举行数

对于每次枚举出来的r行m列,再进行一次动态规划

对于在r行m列中选出c列来,其转移方程就非常容易得到了

\[f[i][j] = min_(f[k][j-1]+w[i]+v[k][i]) \]

其中\(w\)数组是每列中元素的分值

\(v[i][j]\)则是第\(i\)与第\(j\)之间的分值

\(f[i][j]\)是选第\(i\)列作为第\(j\)行最小值

\(f\)数组初始化为$$f[i][1]=w[i]$$

总程序的时间复杂度主要由两部分构成

dfs O(\(C_n^r\))

动态规划 O(\(m^3\))

总时间复杂度为O(\(C_n^rm^3\))


#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

int a[23][233];
int f[233][23];
int v[233][233];
int p[2333];
int w[2333];
int n,m;

int r,c;
int minn=1<<30;

inline void dtgh()
{
	memset(f,0x7f,sizeof(f));
	memset(w,0,sizeof(w));
	memset(v,0,sizeof(v));
	
	
	for(int i=1;i<=m;i++)   
	{
		for(int j=2;j<=r;j++)
		w[i]+=abs(a[p[j-1]][i]-a[p[j]][i]);
	}
	
	for(int i=1;i<=m;i++)
		for(int j=i+1;j<=m;j++)
		{
			if(i == j) continue;
			for(int t=1;t<=r;t++)
			v[i][j]+=abs(a[p[t]][i]-a[p[t]][j]);
		}

	for(int i=1;i<=m;i++)
	{
		f[i][1]=w[i];
	}
	
	for(int i=1;i<=m;i++)
		for(int j=1;j<=min(c,i);j++)
	{
		for(int k=j-1;k<i;k++)
		f[i][j]=min(f[i][j],f[k][j-1]+w[i]+v[k][i]);
		
		
	} 
	
	for(int i=1;i<=m;i++)	
	minn=min(minn,f[i][c]);
}


inline void dfs(int line,int step)
{
	
	
	
	if(step == r+1)
	{
		dtgh();
		return ;
	}
	
	if(line > n) return;
	
	p[step]=line;
	
	dfs(line+1,step+1);
	
	dfs(line+1,step);

    
}

int main()
{
	
	
	ios_base::sync_with_stdio(false);
	cout.tie(NULL);	
	cin.tie(NULL);
	
	cin>>n>>m;
	cin>>r>>c;
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
	{
		cin>>a[i][j];
	}
	
	dfs(1,1);
	
	cout<<minn;
} 

end

posted @ 2020-07-30 18:23  ·Iris  阅读(169)  评论(0编辑  收藏  举报